FRC Paradigm Shift #1259
Documentation for the 2021 Robot
SwerveModule.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2019 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
9 
10 
11 SwerveModule::SwerveModule(int driveMotorChannel,
12  int turningMotorChannel,
13  GetPulseWidthCallback pulseWidthCallback,
14  CANifier::PWMChannel pwmChannel,
15  bool driveMotorReversed,
16  double offset,
17  const std::string& name)
18  : m_offset(offset)
19  , m_name(name)
20  , m_driveMotor(driveMotorChannel)
21  , m_turningMotor(turningMotorChannel, CANSparkMax::MotorType::kBrushless)
22  , m_drivePIDLoader("SM", kDriveAdjust, kDriveP, kDriveI, kDriveD, kDriveFF)
23  , m_turnPIDLoader("SM", kTurnAdjust, kTurnP, kTurnI, kTurnD, kTurnIZ, kTurnIA)
24  , m_pulseWidthCallback(pulseWidthCallback)
25  , m_pwmChannel(pwmChannel)
26 {
27  StatorCurrentLimitConfiguration statorLimit { true, kMotorCurrentLimit, kMotorCurrentLimit, 2 };
28  m_driveMotor.ConfigStatorCurrentLimit(statorLimit);
29  SupplyCurrentLimitConfiguration supplyLimit { true, kMotorCurrentLimit, kMotorCurrentLimit, 2 };
30  m_driveMotor.ConfigSupplyCurrentLimit(supplyLimit);
31  m_turningMotor.SetSmartCurrentLimit(kMotorCurrentLimit);
32 
33  // Set up GetVelocity() to return meters per sec instead of RPM
34  m_turnRelativeEncoder.SetPositionConversionFactor(2.0 * wpi::math::pi / kTurnMotorRevsPerWheelRev);
35 
36  m_driveMotor.SetInverted(driveMotorReversed ? TalonFXInvertType::CounterClockwise : TalonFXInvertType::Clockwise);
37  m_turningMotor.SetInverted(false);
38  m_driveMotor.ConfigSelectedFeedbackSensor(TalonFXFeedbackDevice::IntegratedSensor);
39  m_turnPIDController.SetFeedbackDevice(m_turnRelativeEncoder);
40 
41  m_turningMotor.SetIdleMode(CANSparkMax::IdleMode::kBrake);
42  m_driveMotor.SetNeutralMode(NeutralMode::Brake);
43 
46 
47  m_timer.Reset();
48  m_timer.Start();
49 }
50 
52 {
53  if (m_timer.Get() < 5)
55 
56  double absAngle = CalcAbsoluteAngle();
57  SmartDashboard::PutNumber("D_SM_Rel " + m_name, m_turnRelativeEncoder.GetPosition());
58  SmartDashboard::PutNumber("D_SM_Abs " + m_name, absAngle);
59  SmartDashboard::PutNumber("D_SM_AbsDiff " + m_name, m_turnRelativeEncoder.GetPosition() - absAngle);
60  // SmartDashboard::PutNumber("D_SM_MPS " + m_name, CalcMetersPerSec().to<double>());
61  // SmartDashboard::PutNumber("D_SM_IError " + m_name, m_turnPIDController.GetIAccum());
62  // SmartDashboard::PutNumber("D_SM_TP100MS " + m_name, m_driveMotor.GetSelectedSensorVelocity());
63 }
64 
65 SwerveModuleState SwerveModule::GetState()
66 {
68  return { CalcMetersPerSec(), Rotation2d(radian_t(CalcAbsoluteAngle()))};
69 }
70 
71 void SwerveModule::SetDesiredState(SwerveModuleState &state)
72 {
73  // Retrieving PID values from SmartDashboard if enabled
76 
77  // Get relative encoder position
78  double currentPosition = m_turnRelativeEncoder.GetPosition();
79 
80  // Calculate new turn position given current and desired position
81  bool bOutputReverse = false;
82  double minTurnRads = MinTurnRads(currentPosition, state.angle.Radians().to<double>(), bOutputReverse);
83  double direction = 1.0; // Sent to TalonFX
84  if (bOutputReverse)
85  direction = -1.0;
86 
87  // Set position reference of turnPIDController
88  double newPosition = currentPosition + minTurnRads;
89 
90  if (state.speed != 0_mps) {
91  #ifdef DISABLE_DRIVE
92  m_driveMotor.Set(TalonFXControlMode::Velocity, 0.0);
93  #else
94  m_driveMotor.Set(TalonFXControlMode::Velocity, direction * CalcTicksPer100Ms(state.speed));
95  #endif
96  }
97  else
98  m_driveMotor.Set(TalonFXControlMode::PercentOutput, 0.0);
99 
100  // Set the angle unless module is coming to a full stop
101  if (state.speed.to<double>() != 0.0)
102  m_turnPIDController.SetReference(newPosition, ControlType::kPosition);
103 
104  // SmartDashboard::PutNumber("D_SM_SetpointMPS " + m_name, state.speed.to<double>());
105  // SmartDashboard::PutNumber("D_SM_Error " + m_name, newPosition - m_turnRelativeEncoder.GetPosition());
106 }
107 
109 {
110  m_driveMotor.SetSelectedSensorPosition(0.0);
111 }
112 
114 {
115  double pulseWidth = m_pulseWidthCallback(m_pwmChannel);
116  // Pulse Width per rotation is not equal for all encoders. Some are 0 - 3865, some are 0 - 4096
117  return fmod((pulseWidth - m_offset) * DriveConstants::kPulseWidthToRadians + 2.0 * wpi::math::pi, 2.0 * wpi::math::pi);
118  // SmartDashboard::PutNumber("D_SM_PW " + m_name, pulseWidth);
119  // SmartDashboard::PutNumber("D_SM_AA " + m_name, absAngle);
120  // Convert CW to CCW? absAngle = 2.0 * wpi::math::pi - absAngle;
121 }
122 
124 {
126 }
127 
128 // Determine the smallest magnitude delta angle that can be added to initial angle that will
129 // result in an angle equivalent (but not necessarily equal) to final angle.
130 // All angles in radians
131 //
132 // init final angle1 angle2
133 double SwerveModule::MinTurnRads(double init, double final, bool& bOutputReverse)
134 {
135  init = Util::ZeroTo2PiRads(init);
136  final = Util::ZeroTo2PiRads(final);
137 
138  // The shortest turn angle may be acheived by reversing the motor output direction
139  double angle1 = final - init;
140  double angle2 = final + wpi::math::pi - init;
141 
142  angle1 = Util::NegPiToPiRads(angle1);
143  angle2 = Util::NegPiToPiRads(angle2);
144 
145  // Choose the smallest angle and determine reverse flag
146  //TODO: FINISHED ROBOT TUNING
147  // Eventually prefer angle 1 always during high speed to prevent 180s
148  // if (fabs(angle1) <= 2 * fabs(angle2))
149  // {
150  bOutputReverse = false;
151 
152  return angle1;
153  // }
154  // else
155  // {
156  // bOutputReverse = true;
157 
158  // return angle2;
159  // }
160 }
161 
162 meters_per_second_t SwerveModule::CalcMetersPerSec()
163 {
164  double ticksPer100ms = m_driveMotor.GetSelectedSensorVelocity();
165  return meters_per_second_t(kDriveEncoderMetersPerSec * ticksPer100ms);
166 }
167 
168 double SwerveModule::CalcTicksPer100Ms(meters_per_second_t speed)
169 {
170  return speed.to<double>() / kDriveEncoderMetersPerSec;
171 }
constexpr bool kDriveAdjust
Definition: Constants.h:151
constexpr bool kTurnAdjust
Definition: Constants.h:141
constexpr double kTurnP
Definition: Constants.h:142
constexpr uint kMotorCurrentLimit
Definition: Constants.h:137
static double NegPiToPiRads(double theta)
Definition: Util.cpp:35
constexpr double kTurnIZ
Definition: Constants.h:146
PIDLoaderFalcon m_drivePIDLoader
PID param loader for the TalonFX.
Definition: SwerveModule.h:111
CANEncoder m_turnRelativeEncoder
Definition: SwerveModule.h:105
double CalcTicksPer100Ms(meters_per_second_t speed)
constexpr double kDriveP
Definition: Constants.h:152
void LoadFromNetworkTable(CANPIDController &turnPIDController)
Timer m_timer
Timer used to sync absolute and relative encoders on robot turn on.
Definition: SwerveModule.h:121
meters_per_second_t CalcMetersPerSec()
void LoadFromNetworkTable(TalonFX &driveMotor)
constexpr double kDriveI
Definition: Constants.h:153
double MinTurnRads(double init, double final, bool &bOutputReverse)
string m_name
String used to identify each pod, used for SmartDashboard prints.
Definition: SwerveModule.h:98
GetPulseWidthCallback m_pulseWidthCallback
Definition: SwerveModule.h:117
CANifier::PWMChannel m_pwmChannel
Definition: SwerveModule.h:118
void Load(CANPIDController &turnPIDController)
constexpr double kDriveFF
Definition: Constants.h:155
void SetDesiredState(SwerveModuleState &state)
PIDLoaderNEO m_turnPIDLoader
PID param loader for the CANSparkMax.
Definition: SwerveModule.h:113
CANSparkMax m_turningMotor
Definition: SwerveModule.h:104
static double ZeroTo2PiRads(double theta)
Definition: Util.cpp:15
CANPIDController m_turnPIDController
Definition: SwerveModule.h:107
void Load(TalonFX &driveMotor)
function< double(CANifier::PWMChannel)> GetPulseWidthCallback
Definition: SwerveModule.h:48
void ResetRelativeToAbsolute()
Resync the relative NEO turn encoder to the absolute encoder.
constexpr double kTurnI
Definition: Constants.h:143
constexpr double kPulseWidthToRadians
Definition: Constants.h:99
double m_offset
The offset, in pulse widths, for syncing the relative encoder to the absolute encoder.
Definition: SwerveModule.h:96
double CalcAbsoluteAngle()
Calculate the absolute angle, in radians, based on the pulse widths from m_pulseWidthCallback.
SwerveModuleState GetState()
SwerveModule(int driveMotorChannel, int turningMotorChannel, GetPulseWidthCallback pulseWidthCallback, CANifier::PWMChannel pwmChannel, bool driveEncoderReversed, double offSet, const string &name)
constexpr double kTurnMotorRevsPerWheelRev
Definition: Constants.h:125
constexpr double kDriveEncoderMetersPerSec
Definition: Constants.h:128
constexpr double kTurnIA
Definition: Constants.h:145
constexpr double kTurnD
Definition: Constants.h:144
constexpr double kDriveD
Definition: Constants.h:154
void ResetEncoders()
Resets the drive motor encoders to 0.
TalonFX m_driveMotor
Falon 500 that drives the pod.
Definition: SwerveModule.h:101