CTRE Phoenix 6 C++ 26.50.0-alpha-1
Loading...
Searching...
No Matches
SimSwerveDrivetrain.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) Cross The Road Electronics.Ā  All rights reserved.
3 * License information can be found in CTRE_LICENSE.txt
4 * For support and suggestions contact support@ctr-electronics.com or file
5 * an issue tracker at https://github.com/CrossTheRoadElec/Phoenix-Releases
6 */
7#pragma once
8
12#include <wpi/simulation/DCMotorSim.hpp>
13#include <wpi/math/system/Models.hpp>
14
15namespace ctre {
16namespace phoenix6 {
17namespace swerve {
18
19/**
20 * \brief Simplified swerve drive simulation class.
21 *
22 * This class assumes that the swerve drive is perfect, meaning
23 * that there is no scrub and the wheels do not slip.
24 *
25 * In addition, it assumes the inertia of the robot is governed only
26 * by the inertia of the steer module and the individual drive wheels.
27 * Robot-wide inertia is not accounted for, and neither is translational
28 * vs rotational inertia of the robot.
29 *
30 * These assumptions provide a simplified example that can demonstrate the
31 * behavior of a swerve drive in simulation. Users are encouraged to
32 * expand this model for their own use.
33 */
34template <
35 std::derived_from<hardware::traits::CommonTalon> DriveMotorT,
36 std::derived_from<hardware::traits::CommonTalon> SteerMotorT,
37 typename EncoderT
38>
39 requires std::same_as<EncoderT, hardware::CANcoder> ||
40 std::same_as<EncoderT, hardware::CANdi> ||
41 std::same_as<EncoderT, hardware::TalonFXS>
43protected:
45 public:
46 /** \brief Reference to motor simulation for drive motor */
47 wpi::sim::DCMotorSim DriveMotor;
48 /** \brief Reference to motor simulation for the steer motor */
49 wpi::sim::DCMotorSim SteerMotor;
50 /** \brief Reference to steer gearing for updating encoder */
51 wpi::units::scalar_t DriveGearing;
52 /** \brief Reference to steer gearing for updating encoder */
53 wpi::units::scalar_t SteerGearing;
54 /** \brief Voltage necessary for the drive motor to overcome friction */
55 wpi::units::volt_t DriveFrictionVoltage;
56 /** \brief Voltage necessary for the steer motor to overcome friction */
57 wpi::units::volt_t SteerFrictionVoltage;
58 /** \brief Whether the drive motor is inverted */
60 /** \brief Whether the steer motor is inverted */
62 /** \brief Whether the azimuth encoder is inverted */
64 /** \brief Offset of the azimuth encoder */
65 wpi::units::turn_t EncoderOffset;
66 /** \brief The type of encoder to use for the azimuth */
68
70 wpi::units::scalar_t driveGearing, wpi::units::kilogram_square_meter_t driveInertia,
71 wpi::units::volt_t driveFrictionVoltage, bool driveMotorInverted,
72 DriveMotorArrangement driveMotorType,
73 wpi::units::scalar_t steerGearing, wpi::units::kilogram_square_meter_t steerInertia,
74 wpi::units::volt_t steerFrictionVoltage, bool steerMotorInverted,
75 SteerMotorArrangement steerMotorType,
76 bool encoderInverted,
77 wpi::units::turn_t encoderOffset,
78 SteerFeedbackType encoderType
79 ) :
81 wpi::math::Models::SingleJointedArmFromPhysicalConstants(GetDriveMotorGearbox(driveMotorType), driveInertia, driveGearing),
82 GetDriveMotorGearbox(driveMotorType)
83 },
85 wpi::math::Models::SingleJointedArmFromPhysicalConstants(GetSteerMotorGearbox(steerMotorType), steerInertia, steerGearing),
86 GetSteerMotorGearbox(steerMotorType)
87 },
88 DriveGearing{driveGearing},
89 SteerGearing{steerGearing},
90 DriveFrictionVoltage{driveFrictionVoltage},
91 SteerFrictionVoltage{steerFrictionVoltage},
92 DriveMotorInverted{driveMotorInverted},
93 SteerMotorInverted{steerMotorInverted},
94 EncoderInverted{encoderInverted},
95 EncoderOffset{encoderOffset},
96 EncoderType{encoderType}
97 {}
98
99 static wpi::math::DCMotor GetDriveMotorGearbox(DriveMotorArrangement driveMotorType)
100 {
101 switch (driveMotorType) {
103 default:
104 return wpi::math::DCMotor::KrakenX60FOC(1);
106 return wpi::math::DCMotor::NEO(1);
108 return wpi::math::DCMotor::NeoVortex(1);
109 }
110 }
111
112 static wpi::math::DCMotor GetSteerMotorGearbox(SteerMotorArrangement steerMotorType)
113 {
114 switch (steerMotorType) {
116 default:
117 return wpi::math::DCMotor::KrakenX60FOC(1);
119 return wpi::math::DCMotor{12_V, 3.1_Nm, 202_A, 4_A, 774_rad_per_s, 1};
121 return wpi::math::DCMotor::NEO(1);
123 return wpi::math::DCMotor::NeoVortex(1);
125 return wpi::math::DCMotor::NEO550(1);
129 return wpi::math::DCMotor::CIM(1);
130 }
131 }
132 };
133
135 std::vector<SimSwerveModule> _modules;
136
138 Rotation2d _lastAngle{};
139
140public:
141 template <
142 std::same_as<SwerveModuleConstants<
143 typename DriveMotorT::Configuration,
144 typename SteerMotorT::Configuration,
145 typename EncoderT::Configuration
146 >>... ModuleConstants
147 >
149 std::vector<Translation2d> wheelLocations,
150 sim::Pigeon2SimState &pigeonSim,
151 ModuleConstants const &... moduleConstants
152 ) :
153 _pigeonSim{pigeonSim},
154 _modules{
156 moduleConstants.DriveMotorGearRatio,
157 moduleConstants.DriveInertia,
158 moduleConstants.DriveFrictionVoltage,
159 moduleConstants.DriveMotorInverted,
160 moduleConstants.DriveMotorType,
161 moduleConstants.SteerMotorGearRatio,
162 moduleConstants.SteerInertia,
163 moduleConstants.SteerFrictionVoltage,
164 moduleConstants.SteerMotorInverted,
165 moduleConstants.SteerMotorType,
166 moduleConstants.EncoderInverted,
167 moduleConstants.EncoderOffset,
168 moduleConstants.FeedbackSource
169 }...
170 },
171 _kinem{std::move(wheelLocations)}
172 {}
173
174 void Update(
175 wpi::units::second_t dt,
176 wpi::units::volt_t supplyVoltage,
177 std::span<std::unique_ptr<SwerveModule<DriveMotorT, SteerMotorT, EncoderT>> const> modulesToApply
178 ) {
179 if (modulesToApply.size() != _modules.size()) return;
180
181 std::vector<SwerveModuleVelocity> velocities(modulesToApply.size());
182 /* update our sim devices */
183 for (size_t i = 0; i < modulesToApply.size(); ++i) {
184 auto &driveMotor = modulesToApply[i]->GetDriveMotor().GetSimState();
185 auto &steerMotor = modulesToApply[i]->GetSteerMotor().GetSimState();
186 auto &encoder = modulesToApply[i]->GetEncoder().GetSimState();
187
188 if constexpr (std::same_as<hardware::TalonFXS, DriveMotorT>) {
190 } else {
192 }
193
194 if constexpr (std::same_as<hardware::TalonFXS, SteerMotorT>) {
196 steerMotor.ExtSensorOrientation = _modules[i].SteerMotorInverted != _modules[i].EncoderInverted ? sim::ChassisReference::Clockwise_Positive : sim::ChassisReference::CounterClockwise_Positive;
197 steerMotor.PulseWidthSensorOffset = _modules[i].EncoderOffset;
198 } else {
200 }
201
202 if constexpr (std::same_as<hardware::CANcoder, EncoderT>) {
204 encoder.SensorOffset = _modules[i].EncoderOffset;
205 }
206
207 driveMotor.SetSupplyVoltage(supplyVoltage);
208 steerMotor.SetSupplyVoltage(supplyVoltage);
209 encoder.SetSupplyVoltage(supplyVoltage);
210
211 _modules[i].DriveMotor.SetInputVoltage(AddFriction(driveMotor.GetMotorVoltage(), _modules[i].DriveFrictionVoltage));
212 _modules[i].SteerMotor.SetInputVoltage(AddFriction(steerMotor.GetMotorVoltage(), _modules[i].SteerFrictionVoltage));
213
214 _modules[i].DriveMotor.Update(dt);
215 _modules[i].SteerMotor.Update(dt);
216
217 driveMotor.SetRawRotorPosition(_modules[i].DriveMotor.GetAngularPosition() * _modules[i].DriveGearing);
218 driveMotor.SetRotorVelocity(_modules[i].DriveMotor.GetAngularVelocity() * _modules[i].DriveGearing);
219 driveMotor.SetRotorAcceleration(_modules[i].DriveMotor.GetAngularAcceleration() * _modules[i].DriveGearing);
220
221 steerMotor.SetRawRotorPosition(_modules[i].SteerMotor.GetAngularPosition() * _modules[i].SteerGearing);
222 steerMotor.SetRotorVelocity(_modules[i].SteerMotor.GetAngularVelocity() * _modules[i].SteerGearing);
223 steerMotor.SetRotorAcceleration(_modules[i].SteerMotor.GetAngularAcceleration() * _modules[i].SteerGearing);
224 if constexpr (std::same_as<hardware::TalonFXS, SteerMotorT>) {
225 /* azimuth encoders see the mechanism, so don't account for the steer gearing */
226 steerMotor.SetPulseWidthPosition(_modules[i].SteerMotor.GetAngularPosition());
227 steerMotor.SetPulseWidthVelocity(_modules[i].SteerMotor.GetAngularVelocity());
228 }
229
230 if constexpr (std::same_as<hardware::CANcoder, EncoderT>) {
231 /* azimuth encoders see the mechanism, so don't account for the steer gearing */
232 encoder.SetRawPosition(_modules[i].SteerMotor.GetAngularPosition());
233 encoder.SetVelocity(_modules[i].SteerMotor.GetAngularVelocity());
234 } else if constexpr (std::same_as<hardware::CANdi, EncoderT>) {
235 switch (_modules[i].EncoderType) {
240 encoder.Pwm1SensorOffset = _modules[i].EncoderOffset;
241
242 /* azimuth encoders see the mechanism, so don't account for the steer gearing */
243 encoder.SetPwm1Connected(true);
244 encoder.SetPwm1Position(_modules[i].SteerMotor.GetAngularPosition());
245 encoder.SetPwm1Velocity(_modules[i].SteerMotor.GetAngularVelocity());
246 break;
247
252 encoder.Pwm1SensorOffset = _modules[i].EncoderOffset;
253
254 /* azimuth encoders see the mechanism, so don't account for the steer gearing */
255 encoder.SetPwm2Connected(true);
256 encoder.SetPwm2Position(_modules[i].SteerMotor.GetAngularPosition());
257 encoder.SetPwm2Velocity(_modules[i].SteerMotor.GetAngularVelocity());
258 break;
259
260 default:
261 break;
262 }
263 }
264
265 velocities[i] = modulesToApply[i]->GetCurrentVelocity();
266 }
267
268 auto const angularVel = _kinem.ToChassisVelocities(velocities).omega;
269 _lastAngle = _lastAngle + Rotation2d{angularVel * dt};
270 _pigeonSim.SetRawYaw(_lastAngle.Degrees());
271 _pigeonSim.SetAngularVelocityZ(angularVel);
272 }
273
274protected:
275 /**
276 * \brief Applies the effects of friction to dampen the motor voltage.
277 *
278 * \param motorVoltage Voltage output by the motor
279 * \param frictionVoltage Voltage required to overcome friction
280 * \returns Friction-dampened motor voltage
281 */
282 static wpi::units::volt_t AddFriction(wpi::units::volt_t motorVoltage, wpi::units::volt_t frictionVoltage)
283 {
284 if (wpi::units::math::abs(motorVoltage) < frictionVoltage) {
285 motorVoltage = 0_V;
286 } else if (motorVoltage > 0_V) {
287 motorVoltage -= frictionVoltage;
288 } else {
289 motorVoltage += frictionVoltage;
290 }
291 return motorVoltage;
292 }
293};
294
295}
296}
297}
Class to control the state of a simulated hardware::Pigeon2.
Definition Pigeon2SimState.hpp:31
wpi::sim::DCMotorSim DriveMotor
Reference to motor simulation for drive motor.
Definition SimSwerveDrivetrain.hpp:47
bool SteerMotorInverted
Whether the steer motor is inverted.
Definition SimSwerveDrivetrain.hpp:61
wpi::units::scalar_t SteerGearing
Reference to steer gearing for updating encoder.
Definition SimSwerveDrivetrain.hpp:53
wpi::sim::DCMotorSim SteerMotor
Reference to motor simulation for the steer motor.
Definition SimSwerveDrivetrain.hpp:49
wpi::units::turn_t EncoderOffset
Offset of the azimuth encoder.
Definition SimSwerveDrivetrain.hpp:65
SimSwerveModule(wpi::units::scalar_t driveGearing, wpi::units::kilogram_square_meter_t driveInertia, wpi::units::volt_t driveFrictionVoltage, bool driveMotorInverted, DriveMotorArrangement driveMotorType, wpi::units::scalar_t steerGearing, wpi::units::kilogram_square_meter_t steerInertia, wpi::units::volt_t steerFrictionVoltage, bool steerMotorInverted, SteerMotorArrangement steerMotorType, bool encoderInverted, wpi::units::turn_t encoderOffset, SteerFeedbackType encoderType)
Definition SimSwerveDrivetrain.hpp:69
wpi::units::scalar_t DriveGearing
Reference to steer gearing for updating encoder.
Definition SimSwerveDrivetrain.hpp:51
bool DriveMotorInverted
Whether the drive motor is inverted.
Definition SimSwerveDrivetrain.hpp:59
static wpi::math::DCMotor GetSteerMotorGearbox(SteerMotorArrangement steerMotorType)
Definition SimSwerveDrivetrain.hpp:112
wpi::units::volt_t SteerFrictionVoltage
Voltage necessary for the steer motor to overcome friction.
Definition SimSwerveDrivetrain.hpp:57
bool EncoderInverted
Whether the azimuth encoder is inverted.
Definition SimSwerveDrivetrain.hpp:63
wpi::units::volt_t DriveFrictionVoltage
Voltage necessary for the drive motor to overcome friction.
Definition SimSwerveDrivetrain.hpp:55
static wpi::math::DCMotor GetDriveMotorGearbox(DriveMotorArrangement driveMotorType)
Definition SimSwerveDrivetrain.hpp:99
SteerFeedbackType EncoderType
The type of encoder to use for the azimuth.
Definition SimSwerveDrivetrain.hpp:67
std::vector< SimSwerveModule > _modules
Definition SimSwerveDrivetrain.hpp:135
SimSwerveDrivetrain(std::vector< Translation2d > wheelLocations, sim::Pigeon2SimState &pigeonSim, ModuleConstants const &... moduleConstants)
Definition SimSwerveDrivetrain.hpp:148
impl::SwerveDriveKinematics _kinem
Definition SimSwerveDrivetrain.hpp:137
void Update(wpi::units::second_t dt, wpi::units::volt_t supplyVoltage, std::span< std::unique_ptr< SwerveModule< DriveMotorT, SteerMotorT, EncoderT > > const > modulesToApply)
Definition SimSwerveDrivetrain.hpp:174
static wpi::units::volt_t AddFriction(wpi::units::volt_t motorVoltage, wpi::units::volt_t frictionVoltage)
Applies the effects of friction to dampen the motor voltage.
Definition SimSwerveDrivetrain.hpp:282
Rotation2d _lastAngle
Definition SimSwerveDrivetrain.hpp:138
sim::Pigeon2SimState & _pigeonSim
Definition SimSwerveDrivetrain.hpp:134
Swerve Module class that encapsulates a swerve module powered by CTR Electronics devices.
Definition SwerveModule.hpp:52
Class that converts a chassis velocity (dx, dy, and dtheta components) into individual module states ...
Definition SwerveDriveKinematics.hpp:41
@ Clockwise_Positive
The device should read a clockwise rotation as positive motion.
Definition ChassisReference.hpp:20
@ CounterClockwise_Positive
The device should read a counter-clockwise rotation as positive motion.
Definition ChassisReference.hpp:18
Definition SwerveModule.hpp:28
SteerMotorArrangement
Supported motor arrangements for the steer motors.
Definition SwerveModuleConstants.hpp:49
@ TalonFXS_Brushed_AC
Brushed motor connected to a Talon FXS on terminals A and C.
Definition SwerveModuleConstants.hpp:77
@ TalonFXS_Brushed_AB
Brushed motor connected to a Talon FXS on terminals A and B.
Definition SwerveModuleConstants.hpp:73
@ TalonFX_Integrated
Talon FX integrated brushless motor.
Definition SwerveModuleConstants.hpp:53
@ TalonFXS_Brushed_BC
Brushed motor connected to a Talon FXS on terminals B and C.
Definition SwerveModuleConstants.hpp:81
@ TalonFXS_NEO550_JST
Third party NEO550 brushless motor connected to a Talon FXS over JST.
Definition SwerveModuleConstants.hpp:69
@ TalonFXS_NEO_JST
Third party NEO brushless motor connected to a Talon FXS over JST.
Definition SwerveModuleConstants.hpp:61
@ TalonFXS_VORTEX_JST
Third party VORTEX brushless motor connected to a Talon FXS over JST.
Definition SwerveModuleConstants.hpp:65
@ TalonFXS_Minion_JST
CTR Electronics MinionĀ® brushless motor connected to a Talon FXS over JST.
Definition SwerveModuleConstants.hpp:57
SteerFeedbackType
Supported feedback sensors for the steer motors.
Definition SwerveModuleConstants.hpp:87
@ SyncCANdiPWM2
Requires Pro; Use signals::FeedbackSensorSourceValue::SyncCANdiPWM2 for the steer motor.
Definition SwerveModuleConstants.hpp:122
@ SyncCANdiPWM1
Requires Pro; Use signals::FeedbackSensorSourceValue::SyncCANdiPWM1 for the steer motor.
Definition SwerveModuleConstants.hpp:117
@ RemoteCANdiPWM2
Use signals::FeedbackSensorSourceValue::RemoteCANdiPWM2 for the steer motor.
Definition SwerveModuleConstants.hpp:132
@ FusedCANdiPWM2
Requires Pro; Use signals::FeedbackSensorSourceValue::FusedCANdiPWM2 for the steer motor.
Definition SwerveModuleConstants.hpp:112
@ FusedCANdiPWM1
Requires Pro; Use signals::FeedbackSensorSourceValue::FusedCANdiPWM1 for the steer motor.
Definition SwerveModuleConstants.hpp:107
@ RemoteCANdiPWM1
Use signals::FeedbackSensorSourceValue::RemoteCANdiPWM1 for the steer motor.
Definition SwerveModuleConstants.hpp:127
DriveMotorArrangement
Supported motor arrangements for the drive motors.
Definition SwerveModuleConstants.hpp:31
@ TalonFX_Integrated
Talon FX integrated brushless motor.
Definition SwerveModuleConstants.hpp:35
@ TalonFXS_NEO_JST
Third party NEO brushless motor connected to a Talon FXS over JST.
Definition SwerveModuleConstants.hpp:39
@ TalonFXS_VORTEX_JST
Third party VORTEX brushless motor connected to a Talon FXS over JST.
Definition SwerveModuleConstants.hpp:43
Definition ExternalFeedbackConfigs.hpp:16
Definition motor_constants.h:14
All constants for a swerve module.
Definition SwerveModuleConstants.hpp:148