FRC Paradigm Shift #1259
Documentation for the 2021 Robot
DriveSubsystem.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 
12  : m_frontLeft
13  {
16  , [this](CANifier::PWMChannel channel){ return PWMToPulseWidth(channel); }
20  , string("FrontLeft")
21  }
22  , m_frontRight
23  {
26  , [this](CANifier::PWMChannel channel){ return PWMToPulseWidth(channel); }
30  , string("FrontRight")
31  }
32  , m_rearRight
33  {
36  , [this](CANifier::PWMChannel channel){ return PWMToPulseWidth(channel); }
40  , string("RearRight")
41  }
42  , m_rearLeft
43  {
46  , [this](CANifier::PWMChannel channel){ return PWMToPulseWidth(channel); }
47  , kRearLeftPWM
50  , string("RearLeft")
51  }
53  , m_gyro(gyro)
55 {
56 
57  #ifdef MANUAL_MODULE_STATES
58  SmartDashboard::PutNumber("T_D_MFL", 0);
59  SmartDashboard::PutNumber("T_D_MFR", 0);
60  SmartDashboard::PutNumber("T_D_MRR", 0);
61  SmartDashboard::PutNumber("T_D_MRL", 0);
62  SmartDashboard::PutNumber("T_D_MFLV", 0);
63  SmartDashboard::PutNumber("T_D_MFRV", 0);
64  SmartDashboard::PutNumber("T_D_MRRV", 0);
65  SmartDashboard::PutNumber("T_D_MRLV", 0);
66  #endif
67 
68  #ifdef TUNE_ROTATION_DRIVE
69  SmartDashboard::PutNumber("T_D_RP", 0);
70  SmartDashboard::PutNumber("T_D_RI", 0);
71  SmartDashboard::PutNumber("T_D_RD", 0);
72  SmartDashboard::PutNumber("T_D_RMax", 0);
73  SmartDashboard::PutNumber("T_D_RTMax", 0);
74  #endif
75 
77  m_rotationPIDController.SetIntegratorRange(0, kRotationDriveIMaxRange);
78 
79  m_lastHeading = 0;
80  m_rotationalInput = true;
81 }
82 
84 {
89  , m_rearRight.GetState());
90 
95 }
96 
97 void DriveSubsystem::RotationDrive(meters_per_second_t xSpeed
98  , meters_per_second_t ySpeed
99  , radian_t rot
100  , bool fieldRelative)
101 {
102  double error = rot.to<double>() - m_gyro->GetHeadingAsRot2d().Radians().to<double>();
103  double desiredSet = Util::NegPiToPiRads(error);
104  double max = kRotationDriveMaxSpeed;
105  double maxTurn = kRotationDriveDirectionLimit;
106 
107  #ifdef TUNE_ROTATION_DRIVE
108  double P = SmartDashboard::GetNumber("T_D_RP", 0);
109  double I = SmartDashboard::GetNumber("T_D_RI", 0);
110  double D = SmartDashboard::GetNumber("T_D_RD", 0);
111  double m = SmartDashboard::GetNumber("T_D_RMax", 0);
112  double mTurn = SmartDashboard::GetNumber("T_D_RTMax", 0);
113 
114  m_rotationPIDController.SetP(P);
115  m_rotationPIDController.SetI(I);
116  m_rotationPIDController.SetD(D);
117  max = m;
118  maxTurn = mTurn;
119  #endif
120 
121  double desiredTurnRate = m_rotationPIDController.Calculate(0, desiredSet);
122 
123  double currentTurnRate = m_gyro->GetTurnRate() * wpi::math::pi / 180;
124 
125  // Prevent sharp turning if already fast going in the opposite direction
126  if ((abs(currentTurnRate) >= maxTurn) && (signbit(desiredTurnRate) != signbit(currentTurnRate)))
127  desiredTurnRate *= -1.0;
128 
129  // Power limiting
130  if (abs(desiredTurnRate) > max)
131  desiredTurnRate = signbit(desiredTurnRate) ? max * -1.0 : max;
132 
133  Drive(xSpeed, ySpeed, radians_per_second_t(desiredTurnRate), fieldRelative);
134 }
135 
136 void DriveSubsystem::RotationDrive(meters_per_second_t xSpeed
137  , meters_per_second_t ySpeed
138  , double xRot
139  , double yRot
140  , bool fieldRelative)
141 {
142  if (xRot != 0 || yRot != 0)
143  {
144  m_rotationalInput = true;
145  RotationDrive(xSpeed, ySpeed, radian_t(atan2f(yRot, xRot)), fieldRelative);
146  }
147  else
148  Drive(xSpeed, ySpeed, radians_per_second_t(0), fieldRelative);
149 
150 }
151 
152 void DriveSubsystem::HeadingDrive(meters_per_second_t xSpeed
153  , meters_per_second_t ySpeed
154  , radians_per_second_t rot
155  , bool fieldRelative)
156 {
157  if (xSpeed.to<double>() == 0 && ySpeed.to<double>() == 0 && rot.to<double>() == 0)
158  {
159  Drive(xSpeed, ySpeed, rot, fieldRelative);
160  return;
161  }
162 
163  if (rot.to<double>() == 0 && m_rotationalInput)
164  {
165  m_rotationalInput = false;
167  }
168  else if (rot.to<double>() != 0)
169  m_rotationalInput = true;
170 
171  if (!m_rotationalInput && (xSpeed.to<double>() != 0 || ySpeed.to<double>() != 0))
172  RotationDrive(xSpeed, ySpeed, radian_t(m_lastHeading), fieldRelative);
173  else
174  Drive(xSpeed, ySpeed, rot, fieldRelative);
175 }
176 
177 void DriveSubsystem::Drive(meters_per_second_t xSpeed
178  , meters_per_second_t ySpeed
179  , radians_per_second_t rot
180  , bool fieldRelative)
181 {
182  ChassisSpeeds chassisSpeeds;
183  if (fieldRelative)
184  chassisSpeeds = ChassisSpeeds::FromFieldRelativeSpeeds(xSpeed, ySpeed, rot, m_gyro->GetHeadingAsRot2d());
185  else
186  chassisSpeeds = ChassisSpeeds{xSpeed, ySpeed, rot};
187 
188  auto states = kDriveKinematics.ToSwerveModuleStates(chassisSpeeds);
189 
190  kDriveKinematics.NormalizeWheelSpeeds(&states, kDriveSpeed);
191 
192  #ifdef MANUAL_MODULE_STATES
193  states[kFrontLeft].angle = Rotation2d(radian_t(SmartDashboard::GetNumber("T_D_MFL", 0.0)));
194  states[kFrontRight].angle = Rotation2d(radian_t(SmartDashboard::GetNumber("T_D_MFR", 0.0)));
195  states[kRearRight].angle = Rotation2d(radian_t(SmartDashboard::GetNumber("T_D_MRR", 0.0)));
196  states[kRearLeft].angle = Rotation2d(radian_t(SmartDashboard::GetNumber("T_D_MRL", 0.0)));
197  states[kFrontLeft].speed = SmartDashboard::GetNumber("T_D_MFLV", 0.0) * 1_mps;
198  states[kFrontRight].speed = SmartDashboard::GetNumber("T_D_MFRV", 0.0) * 1_mps;
199  states[kRearRight].speed = SmartDashboard::GetNumber("T_D_MRRV", 0.0) * 1_mps;
200  states[kRearLeft].speed = SmartDashboard::GetNumber("T_D_MRLV", 0.0) * 1_mps;
201  #endif
202 
207 }
208 
210 {
211  kDriveKinematics.NormalizeWheelSpeeds(&desiredStates, AutoConstants::kMaxSpeed);
212  m_frontLeft.SetDesiredState(desiredStates[kFrontLeft]);
213  m_frontRight.SetDesiredState(desiredStates[kFrontRight]);
214  m_rearRight.SetDesiredState(desiredStates[kRearRight]);
215  m_rearLeft.SetDesiredState(desiredStates[kRearLeft]);
216 }
217 
219 {
220  m_lastHeading = m_gyro->GetHeadingAsRot2d().Radians().to<double>();
221 }
222 
224 {
229 }
230 
232 {
233  return m_odometry.GetPose();
234 }
235 
236 double DriveSubsystem::PWMToPulseWidth(CANifier::PWMChannel pwmChannel)
237 {
238  double dutyCycleAndPeriod[2];
239  m_canifier.GetPWMInput(pwmChannel, dutyCycleAndPeriod);
240  return dutyCycleAndPeriod[0] * dutyCycleAndPeriod[1] / kPulseWidthToZeroOne;
241 }
242 
244 {
245  m_odometry.ResetPosition(pose, m_gyro->GetHeadingAsRot2d());
246 }
247 
249 {
254 }
255 
257 {
258  static SwerveModuleState zeroState { 0_mps, 0_deg };
259  printf("DriveSubsystem::WheelsForward() called");
260  m_frontLeft.SetDesiredState(zeroState);
261  m_frontRight.SetDesiredState(zeroState);
262  m_rearRight.SetDesiredState(zeroState);
263  m_rearLeft.SetDesiredState(zeroState);
264 }
constexpr int kCanifierID
CANifier CAN ID (for absolute encoder PWM inputs)
Definition: Constants.h:42
void RotationDrive(meters_per_second_t xSpeed, meters_per_second_t ySpeed, radian_t rot, bool fieldRelative)
frc::Rotation2d GetHeadingAsRot2d()
Definition: Gyro.h:22
constexpr double kFrontRightOffset
Definition: Constants.h:89
void Drive(meters_per_second_t xSpeed, meters_per_second_t ySpeed, radians_per_second_t rot, bool fieldRelative)
double GetTurnRate()
Definition: Gyro.cpp:20
constexpr double kRotationDriveMaxSpeed
Max speed for control.
Definition: Constants.h:109
void Periodic() override
Will be called periodically whenever the CommandScheduler runs.
static double NegPiToPiRads(double theta)
Definition: Util.cpp:35
constexpr CANifier::PWMChannel kFrontRightPWM
Definition: Constants.h:61
constexpr int kRearRightDriveMotorPort
Rear Right Drive CAN ID (TalonFX)
Definition: Constants.h:50
Definition: Gyro.h:14
void ResetRelativeToAbsolute()
Resync all relative NEO turn encoders to the absolute encoders.
SwerveDriveOdometry< DriveConstants::kNumSwerveModules > m_odometry
Odometry class for tracking robot pose.
constexpr int kFrontLeftDriveMotorPort
Front Left Drive CAN ID (TalonFX)
Definition: Constants.h:44
CANifier m_canifier
Reads the absolute encoder pulse widths.
constexpr double kRearRightOffset
Definition: Constants.h:90
constexpr double kRotationDriveTolerance
Tolerance for turning.
Definition: Constants.h:113
constexpr double kRotationDriveDirectionLimit
Speeds higher than value will prevent robot from changing directions for a turn.
Definition: Constants.h:111
frc2::PIDController m_rotationPIDController
PID to control overall robot chassis rotation.
SwerveModule m_frontRight
constexpr int kFrontRightTurningMotorPort
Front Right Turn CAN ID (SparkMAX)
Definition: Constants.h:48
double PWMToPulseWidth(CANifier::PWMChannel pwmChannel)
constexpr int kFrontRightDriveMotorPort
Front Right Drive CAN ID (TalonFX)
Definition: Constants.h:47
wpi::array< SwerveModuleState, DriveConstants::kNumSwerveModules > SwerveModuleStates
Readable alias for array of swerve modules.
void SetDesiredState(SwerveModuleState &state)
double m_lastHeading
Last maintained heading, used for HeadingDrive.
void ResetOdometry(Pose2d pose)
void WheelsForward()
Set all 4 wheels to the zero position.
void UpdateLastHeading()
Updates the last heading set for Heading Drive. Needs to be called if transitioning from other Drive ...
constexpr auto kMaxSpeed
Definition: Constants.h:163
constexpr int kRearLeftDriveMotorPort
Rear Left Drive CAN ID (TalonFX)
Definition: Constants.h:53
constexpr CANifier::PWMChannel kRearLeftPWM
Definition: Constants.h:63
Gyro * m_gyro
Gyro to determine field relative driving, from RobotContainer.
constexpr double kPulseWidthToZeroOne
Definition: Constants.h:98
void ResetRelativeToAbsolute()
Resync the relative NEO turn encoder to the absolute encoder.
constexpr int kFrontLeftTurningMotorPort
Front Left Turn CAN ID (SparkMAX)
Definition: Constants.h:45
constexpr double kRearLeftOffset
Definition: Constants.h:91
void ResetEncoders()
Resets the drive encoders to currently read a position of 0.
constexpr double kFrontLeftOffset
Definition: Constants.h:88
constexpr bool kRearRightDriveMotorReversed
Definition: Constants.h:72
constexpr CANifier::PWMChannel kFrontLeftPWM
Definition: Constants.h:60
constexpr int kRearRightTurningMotorPort
Rear Right Turn CAN ID (SparkMAX)
Definition: Constants.h:51
void HeadingDrive(meters_per_second_t xSpeed, meters_per_second_t ySpeed, radians_per_second_t rot, bool fieldRelative)
constexpr auto kDriveSpeed
Definition: Constants.h:36
constexpr bool kFrontRightDriveMotorReversed
Definition: Constants.h:71
DriveSubsystem(Gyro *gyro)
constexpr bool kRearLeftDriveMotorReversed
Definition: Constants.h:70
SwerveModuleState GetState()
constexpr int kRearLeftTurningMotorPort
Definition: Constants.h:54
constexpr CANifier::PWMChannel kRearRightPWM
Definition: Constants.h:62
constexpr double kRotationDriveIMaxRange
Definition: Constants.h:106
void SetModuleStates(SwerveModuleStates desiredStates)
Sets the drive SpeedControllers to a power from -1 to 1.
void ResetEncoders()
Resets the drive motor encoders to 0.
SwerveModule m_rearRight
constexpr bool kFrontLeftDriveMotorReversed
Definition: Constants.h:69
SwerveDriveKinematics< kNumSwerveModules > kDriveKinematics
The kinematics object converts inputs into 4 individual swerve module turn angle and wheel speeds...
SwerveModule m_frontLeft
bool m_rotationalInput
Whether or not rotation input was provided, used for HeadingDrive.
SwerveModule m_rearLeft