99import static edu .wpi .first .units .Units .Meters ;
1010import static edu .wpi .first .units .Units .Seconds ;
1111
12- import com .ctre .phoenix6 .configs .TalonFXConfiguration ;
13- import com .ctre .phoenix6 .controls .VelocityTorqueCurrentFOC ;
14- import com .ctre .phoenix6 .controls .VoltageOut ;
15- import com .ctre .phoenix6 .hardware .TalonFX ;
16- import com .ctre .phoenix6 .signals .InvertedValue ;
17- import com .ctre .phoenix6 .signals .NeutralModeValue ;
18- import com .ctre .phoenix6 .sim .ChassisReference ;
1912import edu .wpi .first .math .MathUtil ;
2013import edu .wpi .first .math .controller .PIDController ;
14+ import edu .wpi .first .math .controller .SimpleMotorFeedforward ;
2115import edu .wpi .first .math .system .plant .DCMotor ;
2216import edu .wpi .first .math .system .plant .LinearSystemId ;
23- import edu .wpi .first .wpilibj .RobotController ;
2417import edu .wpi .first .wpilibj .simulation .DCMotorSim ;
2518import wmironpatriots .Constants ;
2619import wmironpatriots .subsystems .Swerve .SwerveConstants ;
2720import wmironpatriots .subsystems .Swerve .SwerveConstants .ModuleConfig ;
2821
2922public class ModuleHardwareSim implements ModuleHardware {
23+ public static final double PIVOT_REDUCTION = 150 / 7 ;
24+ public static final double DRIVE_REDUCTION = 6.12 ;
25+
3026 private final int index ;
3127
3228 private final DCMotor pivotModel = DCMotor .getKrakenX60Foc (1 );
3329 private final DCMotor driveModel = DCMotor .getKrakenX60Foc (1 );
3430
3531 private final DCMotorSim pivotSim , driveSim ;
36- private final TalonFX drive ;
37- private final TalonFXConfiguration driveCfg ;
38-
39- private final VoltageOut voltReq = new VoltageOut (0.0 );
40- private final VelocityTorqueCurrentFOC velReq = new VelocityTorqueCurrentFOC (0.0 );
32+ private double pivotAppliedVolts , driveAppliedVolts ;
4133
42- private double lastUpdateTimestamp = 0.0 ;
43- private double pivotAppliedVolts = 0.0 ;
44-
45- private final PIDController pivotFeedback = new PIDController (1 , 0.0 , 0.0 );
34+ private PIDController pivotFeedback = new PIDController (50.0 , 0.0 , 0.0 );
35+ private PIDController driveFeedback = new PIDController (3.2 , 0.0 , 0.0 );
36+ private SimpleMotorFeedforward driveFeedforward = new SimpleMotorFeedforward (0.233 , 2.02 , 0.05 );
4637
4738 public ModuleHardwareSim (ModuleConfig moduleConfig ) {
4839 index = moduleConfig .index ();
4940
5041 pivotSim =
5142 new DCMotorSim (
52- LinearSystemId .createDCMotorSystem (pivotModel , 0.004 , 21.428571428571427 ),
53- pivotModel ,
54- 0.0 ,
55- 0.0 );
43+ LinearSystemId .createDCMotorSystem (pivotModel , 0.004 , 150 / 7 ), pivotModel , 0.0 , 0.0 );
5644
5745 driveSim =
5846 new DCMotorSim (
59- LinearSystemId .createDCMotorSystem (driveModel , 0.025 , 6.122448979591837 ),
60- driveModel ,
61- 0.0 ,
62- 0.0 );
63-
64- drive = new TalonFX (moduleConfig .driveId ().getId (), moduleConfig .driveId ().getBusName ());
65-
66- // Drive Configs
67- driveCfg = new TalonFXConfiguration ();
68- // Current limits
69- driveCfg .CurrentLimits .SupplyCurrentLimit = 40.0 ;
70- driveCfg .CurrentLimits .SupplyCurrentLimitEnable = true ;
71- driveCfg .CurrentLimits .StatorCurrentLimit = 120.0 ;
72- driveCfg .CurrentLimits .StatorCurrentLimitEnable = true ;
73- // Inverts
74- driveCfg .MotorOutput .Inverted = InvertedValue .Clockwise_Positive ;
75- driveCfg .MotorOutput .NeutralMode = NeutralModeValue .Brake ;
76- // Sensor
77- // Meters per second
78- driveCfg .Feedback .SensorToMechanismRatio = 6.122448979591837 ;
79- // Current control gains
80- // Gains copied from AlphaSwerveConstants
81- driveCfg .Slot0 .kV = 5.0 ;
82- // kT (stall torque / stall current) converted to linear wheel frame
83- driveCfg .Slot0 .kA = 0.0 ; // (9.37 / 483.0) / getDriveRotorToMeters(); // 3.07135116146;
84- driveCfg .Slot0 .kS = 10.0 ;
85- driveCfg .Slot0 .kP = 1.0 ;
86- driveCfg .Slot0 .kD = 0.0 ; // 1.0;
87-
88- driveCfg .TorqueCurrent .TorqueNeutralDeadband = 10.0 ;
89-
90- drive .getConfigurator ().apply (driveCfg );
91-
92- drive .getSimState ().Orientation =
93- driveCfg .MotorOutput .Inverted == InvertedValue .CounterClockwise_Positive
94- ? ChassisReference .CounterClockwise_Positive
95- : ChassisReference .Clockwise_Positive ;
96- }
47+ LinearSystemId .createDCMotorSystem (driveModel , 0.025 , 6.12 ), driveModel , 0.0 , 0.0 );
9748
98- private double addFriction (double motorVoltage , double frictionVoltage ) {
99- if (Math .abs (motorVoltage ) < frictionVoltage ) {
100- motorVoltage = 0.0 ;
101- } else if (motorVoltage > 0.0 ) {
102- motorVoltage -= frictionVoltage ;
103- } else {
104- motorVoltage += frictionVoltage ;
105- }
106- return motorVoltage ;
49+ pivotFeedback .enableContinuousInput (0 , 0.5 );
10750 }
10851
10952 @ Override
11053 public LoggableState getLoggableState () {
111- var driveSimState = drive .getSimState ();
112- double driveSimVolts = addFriction (driveSimState .getMotorVoltage (), 0.25 );
113-
114- driveSim .setInput (driveSimVolts );
115- double timestamp = RobotController .getFPGATime ();
11654 pivotSim .update (Constants .LOOPTIME .in (Seconds ));
11755 driveSim .update (Constants .LOOPTIME .in (Seconds ));
118- lastUpdateTimestamp = timestamp ;
119-
120- driveSimState .setRotorVelocity (
121- (driveSim .getAngularVelocityRPM () / 60.0 ) * driveCfg .Feedback .SensorToMechanismRatio );
12256
12357 return new LoggableState (
12458 index ,
@@ -131,12 +65,31 @@ public LoggableState getLoggableState() {
13165 true ,
13266 driveSim .getAngularPositionRad () * SwerveConstants .WHEEL_RADIUS .in (Meters ),
13367 driveSim .getAngularVelocityRadPerSec () * SwerveConstants .WHEEL_RADIUS .in (Meters ),
134- 0.0 ,
135- drive . getSimState (). getMotorVoltage () ,
68+ driveFeedback . getSetpoint () ,
69+ driveAppliedVolts ,
13670 driveSim .getCurrentDrawAmps (),
13771 pivotSim .getTorqueNewtonMeters () / driveModel .KtNMPerAmp ,
13872 true ,
139- pivotSim .getAngularPositionRad ());
73+ pivotSim .getAngularPositionRotations ());
74+ }
75+
76+ private double addFriction (double motorVoltage , double frictionVoltage ) {
77+ if (Math .abs (motorVoltage ) < frictionVoltage ) {
78+ motorVoltage = 0.0 ;
79+ } else if (motorVoltage > 0.0 ) {
80+ motorVoltage -= frictionVoltage ;
81+ } else {
82+ motorVoltage += frictionVoltage ;
83+ }
84+ return motorVoltage ;
85+ }
86+
87+ /**
88+ * @return the drive motor speed in Meters per Second
89+ */
90+ private double getDriveSpeedMps () {
91+ return (driveSim .getAngularVelocityRPM () / 60 )
92+ * (SwerveConstants .WHEEL_RADIUS .in (Meters ) * 2 * Math .PI );
14093 }
14194
14295 @ Override
@@ -147,7 +100,8 @@ public void setPivotAppliedVolts(double volts) {
147100
148101 @ Override
149102 public void setDriveAppliedVolts (double volts ) {
150- drive .setControl (voltReq .withOutput (volts ));
103+ driveAppliedVolts = MathUtil .clamp (volts , -12.0 , 12.0 );
104+ driveSim .setInputVoltage (driveAppliedVolts );
151105 }
152106
153107 @ Override
@@ -157,13 +111,13 @@ public void setPivotSetpointPose(double poseRevs) {
157111
158112 @ Override
159113 public void setDriveSetpointSpeed (double speedMps ) {
160- drive . setControl ( velReq . withVelocity ( speedMps ));
114+ setDriveAppliedVolts ( driveFeedback . calculate ( getDriveSpeedMps (), speedMps ));
161115 }
162116
163117 @ Override
164118 public void stop () {
165119 pivotSim .setInputVoltage (0.0 );
166- drive . stopMotor ( );
120+ driveSim . setInputVoltage ( 0.0 );
167121 }
168122
169123 @ Override
0 commit comments