From 12757a6d363da9aff2fd6a851822fb5892e5f07d Mon Sep 17 00:00:00 2001 From: BenGener3 Date: Tue, 4 Aug 2026 20:00:06 -0400 Subject: [PATCH 1/7] changed limits --- .../frc/robot/subsystems/launcher/LauncherConstants.java | 6 +++--- .../java/frc/robot/subsystems/launcher/TurretIOSpark.java | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java index a01a923..06ab682 100644 --- a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java +++ b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java @@ -76,10 +76,10 @@ public static final class TurretConstants { // Geometry public static final Transform3d CHASSIS_TO_TURRET_BASE = new Transform3d(Inches.of(-4.000), Inches.of(6.500), Inches.of(16.331), Rotation3d.kZero); - public static final Rotation2d ABS_ENCODER_OFFSET = new Rotation2d(5.157); + public static final Rotation2d ABS_ENCODER_OFFSET = new Rotation2d(5.157 + 1.267); public static final Rotation2d MECHANISM_OFFSET = Rotation2d.kZero; - public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(270); - public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(45); + public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(100); + public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-10); public static final double MARGIN_RAD = Units.degreesToRadians(5); // Position controller diff --git a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java index 48760c2..234d09e 100644 --- a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java +++ b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java @@ -128,9 +128,12 @@ public void setOpenLoop(Voltage volts) { @Override public void setPosition(Rotation2d rotation, AngularVelocity angularVelocity) { + double center = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; double setpoint = MathUtil.inputModulus( - rotation.getRadians() - MECHANISM_OFFSET.getRadians(), 0.0, 2 * Math.PI); + rotation.getRadians() - MECHANISM_OFFSET.getRadians(), + center - Math.PI, + center + Math.PI); double clampedSetpoint = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD, UPPER_LIMIT_RAD); double clampedSetpointWithMargin = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD + MARGIN_RAD, UPPER_LIMIT_RAD - MARGIN_RAD); From 2adb7ae28f86286b99e3a18cd662ce6ed993948e Mon Sep 17 00:00:00 2001 From: BenGener3 Date: Tue, 4 Aug 2026 20:18:14 -0400 Subject: [PATCH 2/7] changed more limits --- .../java/frc/robot/subsystems/launcher/LauncherConstants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java index 06ab682..a78eb70 100644 --- a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java +++ b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java @@ -78,8 +78,8 @@ public static final class TurretConstants { new Transform3d(Inches.of(-4.000), Inches.of(6.500), Inches.of(16.331), Rotation3d.kZero); public static final Rotation2d ABS_ENCODER_OFFSET = new Rotation2d(5.157 + 1.267); public static final Rotation2d MECHANISM_OFFSET = Rotation2d.kZero; - public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(100); - public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-10); + public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(0); + public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-45); public static final double MARGIN_RAD = Units.degreesToRadians(5); // Position controller From c96f3f8bea5c70ccd03b1b819da2b498975301f7 Mon Sep 17 00:00:00 2001 From: Nate Laverdure Date: Tue, 4 Aug 2026 20:38:07 -0400 Subject: [PATCH 3/7] seed the turret position on the manifold --- .../java/frc/robot/subsystems/launcher/TurretIOSpark.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java index 234d09e..d55fd02 100644 --- a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java +++ b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java @@ -98,7 +98,13 @@ public TurretIOSpark() { @Override public void updateInputs(TurretIOInputs inputs) { if (!relativeEncoderSeeded && inputs.absoluteEncoderConnected) { - turnSparkEncoder.setPosition(absoluteEncoder.get()); + double center = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; + double seedPosition = + MathUtil.inputModulus( + absoluteEncoder.get() - MECHANISM_OFFSET.getRadians(), + center - Math.PI, + center + Math.PI); + turnSparkEncoder.setPosition(seedPosition); relativeEncoderSeeded = true; } From 7ba3042eaf003c63885e87647afbfcf5439dbf77 Mon Sep 17 00:00:00 2001 From: BenGener3 Date: Tue, 4 Aug 2026 20:46:42 -0400 Subject: [PATCH 4/7] limits changed again --- .../java/frc/robot/subsystems/launcher/LauncherConstants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java index a78eb70..c94484e 100644 --- a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java +++ b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java @@ -78,8 +78,8 @@ public static final class TurretConstants { new Transform3d(Inches.of(-4.000), Inches.of(6.500), Inches.of(16.331), Rotation3d.kZero); public static final Rotation2d ABS_ENCODER_OFFSET = new Rotation2d(5.157 + 1.267); public static final Rotation2d MECHANISM_OFFSET = Rotation2d.kZero; - public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(0); - public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-45); + public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(30); + public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-280); public static final double MARGIN_RAD = Units.degreesToRadians(5); // Position controller From ed717aa1c19173a7aa8497561551b8b230f0e5a7 Mon Sep 17 00:00:00 2001 From: Nate Laverdure Date: Tue, 4 Aug 2026 20:56:54 -0400 Subject: [PATCH 5/7] Share turret wrap-window center via a constant, fix sim to match real IO TurretIOSpark computed the modulus center inline; extract it into CENTER_RAD so both it and TurretIOSimSpark derive the wrap window from the same source. TurretIOSimSpark was still using the old hardcoded [0, 2*pi) wrap, which breaks for any operating range that isn't [0, 360) - bring it in line with the real IO's centered window. Co-Authored-By: Claude Sonnet 5 --- .../robot/subsystems/launcher/LauncherConstants.java | 1 + .../robot/subsystems/launcher/TurretIOSimSpark.java | 9 +++++++-- .../frc/robot/subsystems/launcher/TurretIOSpark.java | 10 ++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java index c94484e..9896040 100644 --- a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java +++ b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java @@ -80,6 +80,7 @@ public static final class TurretConstants { public static final Rotation2d MECHANISM_OFFSET = Rotation2d.kZero; public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(30); public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-280); + public static final double CENTER_RAD = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; public static final double MARGIN_RAD = Units.degreesToRadians(5); // Position controller diff --git a/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java b/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java index db1f0b9..4695890 100644 --- a/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java +++ b/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java @@ -78,7 +78,10 @@ public TurretIOSimSpark() { LinearSystemId.createDCMotorSystem(GEARBOX, TURRET_MOI_KG_M2, MOTOR_REDUCTION), GEARBOX); - turnSim.setState(2.0 * Math.PI - MECHANISM_OFFSET.getRadians(), 0); + double seedPosition = + MathUtil.inputModulus( + 2.0 * Math.PI - MECHANISM_OFFSET.getRadians(), CENTER_RAD - Math.PI, CENTER_RAD + Math.PI); + turnSim.setState(seedPosition, 0); turnSparkSim.setPosition(turnSim.getAngularPositionRad()); } @@ -116,7 +119,9 @@ public void setOpenLoop(Voltage volts) { public void setPosition(Rotation2d rotation, AngularVelocity angularVelocity) { double setpoint = MathUtil.inputModulus( - rotation.getRadians() - MECHANISM_OFFSET.getRadians(), 0.0, 2.0 * Math.PI); + rotation.getRadians() - MECHANISM_OFFSET.getRadians(), + CENTER_RAD - Math.PI, + CENTER_RAD + Math.PI); double clampedSetpoint = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD, UPPER_LIMIT_RAD); double clampedSetpointWithMargin = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD + MARGIN_RAD, UPPER_LIMIT_RAD - MARGIN_RAD); diff --git a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java index d55fd02..0ac80d6 100644 --- a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java +++ b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java @@ -98,12 +98,11 @@ public TurretIOSpark() { @Override public void updateInputs(TurretIOInputs inputs) { if (!relativeEncoderSeeded && inputs.absoluteEncoderConnected) { - double center = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; double seedPosition = MathUtil.inputModulus( absoluteEncoder.get() - MECHANISM_OFFSET.getRadians(), - center - Math.PI, - center + Math.PI); + CENTER_RAD - Math.PI, + CENTER_RAD + Math.PI); turnSparkEncoder.setPosition(seedPosition); relativeEncoderSeeded = true; } @@ -134,12 +133,11 @@ public void setOpenLoop(Voltage volts) { @Override public void setPosition(Rotation2d rotation, AngularVelocity angularVelocity) { - double center = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; double setpoint = MathUtil.inputModulus( rotation.getRadians() - MECHANISM_OFFSET.getRadians(), - center - Math.PI, - center + Math.PI); + CENTER_RAD - Math.PI, + CENTER_RAD + Math.PI); double clampedSetpoint = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD, UPPER_LIMIT_RAD); double clampedSetpointWithMargin = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD + MARGIN_RAD, UPPER_LIMIT_RAD - MARGIN_RAD); From d370591db3013d044b3eb5ef7b0cf865d5a28297 Mon Sep 17 00:00:00 2001 From: Nate Laverdure Date: Tue, 4 Aug 2026 20:57:46 -0400 Subject: [PATCH 6/7] Remove redundant MECHANISM_OFFSET turret constant Always zero, and layered on top of ABS_ENCODER_OFFSET in a way that was hazardous rather than useful: it cancelled out of every reported position, but shifted the soft limits away from true forward if ever set nonzero, with nothing visible to indicate the mismatch. ABS_ENCODER_OFFSET is the single source of truth for where forward is. Co-Authored-By: Claude Sonnet 5 --- .../subsystems/launcher/LauncherConstants.java | 1 - .../subsystems/launcher/TurretIOSimSpark.java | 12 ++++-------- .../robot/subsystems/launcher/TurretIOSpark.java | 14 ++++---------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java index 9896040..cf1beb4 100644 --- a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java +++ b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java @@ -77,7 +77,6 @@ public static final class TurretConstants { public static final Transform3d CHASSIS_TO_TURRET_BASE = new Transform3d(Inches.of(-4.000), Inches.of(6.500), Inches.of(16.331), Rotation3d.kZero); public static final Rotation2d ABS_ENCODER_OFFSET = new Rotation2d(5.157 + 1.267); - public static final Rotation2d MECHANISM_OFFSET = Rotation2d.kZero; public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(30); public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-280); public static final double CENTER_RAD = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; diff --git a/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java b/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java index 4695890..1577ec7 100644 --- a/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java +++ b/src/main/java/frc/robot/subsystems/launcher/TurretIOSimSpark.java @@ -79,8 +79,7 @@ public TurretIOSimSpark() { GEARBOX); double seedPosition = - MathUtil.inputModulus( - 2.0 * Math.PI - MECHANISM_OFFSET.getRadians(), CENTER_RAD - Math.PI, CENTER_RAD + Math.PI); + MathUtil.inputModulus(2.0 * Math.PI, CENTER_RAD - Math.PI, CENTER_RAD + Math.PI); turnSim.setState(seedPosition, 0); turnSparkSim.setPosition(turnSim.getAngularPositionRad()); } @@ -96,13 +95,13 @@ public void updateInputs(TurretIOInputs inputs) { // Update inputs inputs.motorControllerConnected = true; - inputs.relativePosition = new Rotation2d(turnSparkSim.getPosition()).plus(MECHANISM_OFFSET); + inputs.relativePosition = new Rotation2d(turnSparkSim.getPosition()); inputs.velocityRadPerSec = turnSparkSim.getVelocity(); inputs.appliedVolts = turnSparkSim.getAppliedOutput() * turnSparkSim.getBusVoltage(); inputs.currentAmps = Math.abs(turnSparkSim.getMotorCurrent()); inputs.absoluteEncoderConnected = true; - inputs.absolutePosition = new Rotation2d(turnSparkSim.getPosition()).plus(MECHANISM_OFFSET); + inputs.absolutePosition = new Rotation2d(turnSparkSim.getPosition()); inputs.oversaturation = oversaturation; inputs.oversaturationLessMargin = oversaturationLessMargin; @@ -118,10 +117,7 @@ public void setOpenLoop(Voltage volts) { @Override public void setPosition(Rotation2d rotation, AngularVelocity angularVelocity) { double setpoint = - MathUtil.inputModulus( - rotation.getRadians() - MECHANISM_OFFSET.getRadians(), - CENTER_RAD - Math.PI, - CENTER_RAD + Math.PI); + MathUtil.inputModulus(rotation.getRadians(), CENTER_RAD - Math.PI, CENTER_RAD + Math.PI); double clampedSetpoint = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD, UPPER_LIMIT_RAD); double clampedSetpointWithMargin = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD + MARGIN_RAD, UPPER_LIMIT_RAD - MARGIN_RAD); diff --git a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java index 0ac80d6..1416520 100644 --- a/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java +++ b/src/main/java/frc/robot/subsystems/launcher/TurretIOSpark.java @@ -54,7 +54,7 @@ public TurretIOSpark() { new DutyCycleEncoder( new DigitalInput(DIOPorts.TURRET_ABS_ENCODER), 2 * Math.PI, - ABS_ENCODER_OFFSET.getRadians() + MECHANISM_OFFSET.getRadians()); + ABS_ENCODER_OFFSET.getRadians()); var turnConfig = new SparkMaxConfig(); @@ -99,16 +99,13 @@ public TurretIOSpark() { public void updateInputs(TurretIOInputs inputs) { if (!relativeEncoderSeeded && inputs.absoluteEncoderConnected) { double seedPosition = - MathUtil.inputModulus( - absoluteEncoder.get() - MECHANISM_OFFSET.getRadians(), - CENTER_RAD - Math.PI, - CENTER_RAD + Math.PI); + MathUtil.inputModulus(absoluteEncoder.get(), CENTER_RAD - Math.PI, CENTER_RAD + Math.PI); turnSparkEncoder.setPosition(seedPosition); relativeEncoderSeeded = true; } // Read from cached values (non-blocking) - updated by SparkOdometryThread - inputs.relativePosition = new Rotation2d(sparkInputs.getPosition()).plus(MECHANISM_OFFSET); + inputs.relativePosition = new Rotation2d(sparkInputs.getPosition()); inputs.velocityRadPerSec = sparkInputs.getVelocity(); inputs.appliedVolts = sparkInputs.getAppliedVolts(); inputs.currentAmps = sparkInputs.getOutputCurrent(); @@ -134,10 +131,7 @@ public void setOpenLoop(Voltage volts) { @Override public void setPosition(Rotation2d rotation, AngularVelocity angularVelocity) { double setpoint = - MathUtil.inputModulus( - rotation.getRadians() - MECHANISM_OFFSET.getRadians(), - CENTER_RAD - Math.PI, - CENTER_RAD + Math.PI); + MathUtil.inputModulus(rotation.getRadians(), CENTER_RAD - Math.PI, CENTER_RAD + Math.PI); double clampedSetpoint = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD, UPPER_LIMIT_RAD); double clampedSetpointWithMargin = MathUtil.clamp(setpoint, LOWER_LIMIT_RAD + MARGIN_RAD, UPPER_LIMIT_RAD - MARGIN_RAD); From 717375800a0a4671e3354b5dcabef02715c7a73f Mon Sep 17 00:00:00 2001 From: Nate Laverdure Date: Tue, 4 Aug 2026 20:58:07 -0400 Subject: [PATCH 7/7] Document turret coordinate convention for future reclocking Explain the forward/CCW angle convention, what ABS_ENCODER_OFFSET calibrates and how to redo it, the meaning and constraint on the soft limits, and that CENTER_RAD is derived rather than hand-set. Co-Authored-By: Claude Sonnet 5 --- .../subsystems/launcher/LauncherConstants.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java index cf1beb4..7870ed2 100644 --- a/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java +++ b/src/main/java/frc/robot/subsystems/launcher/LauncherConstants.java @@ -76,9 +76,26 @@ public static final class TurretConstants { // Geometry public static final Transform3d CHASSIS_TO_TURRET_BASE = new Transform3d(Inches.of(-4.000), Inches.of(6.500), Inches.of(16.331), Rotation3d.kZero); + // Turret angle convention: 0 / 2*pi rad = forward, increasing CCW (viewed from above), + // matching standard Rotation2d/WPILib handedness. All constants below are w/r/t forward. + + // Calibration value chosen so the absolute encoder reads 0 / 2*pi when the turret is + // physically facing forward. To reclock after a mechanical rebuild or encoder reseat: point + // the turret forward by hand, read the raw absolute encoder value (with this offset backed + // out, i.e. temporarily zeroed), and set ABS_ENCODER_OFFSET to that raw reading. public static final Rotation2d ABS_ENCODER_OFFSET = new Rotation2d(5.157 + 1.267); + + // Soft limits of the mechanical range, measured CCW from forward (e.g. LOWER=-280 means the + // turret can travel 280 deg clockwise of forward). UPPER_LIMIT_RAD - LOWER_LIMIT_RAD must + // stay under 360 deg, or the wrap math below (CENTER_RAD, and its use in TurretIOSpark / + // TurretIOSimSpark) can no longer place every reachable angle in a single unambiguous branch. public static final double UPPER_LIMIT_RAD = Units.degreesToRadians(30); public static final double LOWER_LIMIT_RAD = Units.degreesToRadians(-280); + + // Center of the operating range. Used to pick the modulus window ([CENTER-pi, CENTER+pi)) + // that setpoints and the relative-encoder seed get wrapped into, so the branch cut always + // falls in the unreachable gap directly opposite the range rather than inside it. Derived + // automatically from the limits above - do not hand-edit when reclocking. public static final double CENTER_RAD = (LOWER_LIMIT_RAD + UPPER_LIMIT_RAD) / 2.0; public static final double MARGIN_RAD = Units.degreesToRadians(5);