1212import static frc .robot .subsystems .drive .DriveConstants .*;
1313import static frc .robot .util .SparkUtil .*;
1414
15+ import com .revrobotics .AbsoluteEncoder ;
1516import com .revrobotics .PersistMode ;
1617import com .revrobotics .RelativeEncoder ;
1718import com .revrobotics .ResetMode ;
2627import com .revrobotics .spark .config .SparkBaseConfig .IdleMode ;
2728import com .revrobotics .spark .config .SparkMaxConfig ;
2829import edu .wpi .first .math .MathUtil ;
30+ import edu .wpi .first .math .controller .PIDController ;
2931import edu .wpi .first .math .filter .Debouncer ;
3032import edu .wpi .first .math .geometry .Rotation2d ;
31- import edu . wpi . first . wpilibj . AnalogEncoder ;
33+ import frc . robot . util . AbsoluteAnalogEncoder ;
3234import java .util .Queue ;
3335import java .util .function .DoubleSupplier ;
3436
@@ -50,6 +52,8 @@ public class ModuleIOSpark implements ModuleIO {
5052 // Closed loop controllers
5153 private final SparkClosedLoopController driveController ;
5254 private final SparkClosedLoopController turnController ;
55+ // RIO-side PID for turn control (we use the RoboRIO analog absolute encoder)
56+ private final PIDController turnPid ;
5357
5458 // Queue inputs from odometry thread
5559 private final Queue <Double > timestampQueue ;
@@ -107,6 +111,12 @@ public ModuleIOSpark(int module) {
107111 driveController = driveSpark .getClosedLoopController ();
108112 turnController = turnSpark .getClosedLoopController ();
109113
114+ // RIO-side PID controller for the turn motor. We use the RoboRIO-mounted
115+ // analog absolute encoder (turnEncoder) as the measurement and command
116+ // voltages to the SPARK via setVoltage(...).
117+ turnPid = new PIDController (turnKp , 0.0 , turnKd );
118+ turnPid .enableContinuousInput (turnPIDMinInput , turnPIDMaxInput );
119+
110120 // Configure drive motor
111121 var driveConfig = new SparkMaxConfig ();
112122 driveConfig
@@ -157,8 +167,7 @@ public ModuleIOSpark(int module) {
157167 .closedLoop
158168 .feedbackSensor (FeedbackSensor .kPrimaryEncoder )
159169 .positionWrappingEnabled (true )
160- .positionWrappingInputRange (turnPIDMinInput , turnPIDMaxInput )
161- .pid (turnKp , 0.0 , turnKd );
170+ .positionWrappingInputRange (turnPIDMinInput , turnPIDMaxInput );
162171 turnConfig
163172 .signals
164173 .primaryEncoderPositionAlwaysOn (true )
@@ -183,6 +192,10 @@ public ModuleIOSpark(int module) {
183192 timestampQueue = SparkOdometryThread .getInstance ().makeTimestampQueue ();
184193 drivePositionQueue =
185194 SparkOdometryThread .getInstance ().registerSignal (driveSpark , driveEncoder ::getPosition );
195+ // The turn encoder is an external RoboRIO-mounted analog encoder (not a Spark signal).
196+ // Register it as a generic DoubleSupplier so the odometry thread samples it directly
197+ // instead of going through the Spark-specific sampling/error path which can drop
198+ // or mis-time samples for a non-Spark sensor and produce jitter in AdvantageScope.
186199 turnPositionQueue =
187200 SparkOdometryThread .getInstance ().registerSignal (turnSpark , turnEncoder ::getPosition );
188201 //// MODIFIED
@@ -213,7 +226,8 @@ public void updateInputs(ModuleIOInputs inputs) {
213226 new DoubleSupplier [] {turnSpark ::getAppliedOutput , turnSpark ::getBusVoltage },
214227 (values ) -> inputs .turnAppliedVolts = values [0 ] * values [1 ]);
215228 ifOk (turnSpark , turnSpark ::getOutputCurrent , (value ) -> inputs .turnCurrentAmps = value );
216- inputs .turnConnected = turnConnectedDebounce .calculate (!sparkStickyFault );
229+ // Use the analog-read success as our connected indicator for turn.
230+ inputs .turnConnected = turnConnectedDebounce .calculate (turnReadOk );
217231
218232 // Update odometry inputs
219233 inputs .odometryTimestamps =
@@ -255,6 +269,14 @@ public void setTurnPosition(Rotation2d rotation) {
255269 double setpoint =
256270 MathUtil .inputModulus (
257271 rotation .plus (zeroRotation ).getRadians (), turnPIDMinInput , turnPIDMaxInput );
258- turnController .setSetpoint (setpoint , ControlType .kPosition );
272+
273+ // Read the RoboRIO-mounted analog absolute encoder and compute PID output
274+ double current = turnEncoder .getPosition ();
275+ double volts = turnPid .calculate (current , setpoint );
276+
277+ // Clamp to allowable voltage range
278+ volts = MathUtil .clamp (volts , -12.0 , 12.0 );
279+
280+ turnSpark .setVoltage (volts );
259281 }
260282}
0 commit comments