The basic issue we were having was not having the latest Phoenix library. We wanted to use a DifferentialDrive in our Drive train subsystem class, but the constructor wanted the a MotorController type and we couldn’t find a class for a Falcon 500 that extended from MotorController.
The fix was to manage vendor libraries, which you can get to by right clicking on the build.gradle file in the visual studio code tree. (instructions here: FRC: VS Code C++/Java — Phoenix documentation (ctre-phoenix.com)
Our robot uses subsystems and the code for our drive train is below:
package frc.robot.subsystems;
import com.ctre.phoenix.motorcontrol.Faults;
import com.ctre.phoenix.motorcontrol.FeedbackDevice;
import com.ctre.phoenix.motorcontrol.InvertType;
import com.ctre.phoenix.motorcontrol.TalonFXInvertType;
import com.ctre.phoenix.motorcontrol.can.TalonFX;
import com.ctre.phoenix.motorcontrol.can.TalonFXConfiguration;
import com.ctre.phoenix.motorcontrol.can.WPI_TalonFX;
import edu.wpi.first.wpilibj2.command.Subsystem;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import edu.wpi.first.wpilibj.drive.DifferentialDrive;
import edu.wpi.first.wpilibj.motorcontrol.MotorControllerGroup;
import frc.robot.Constants.DriveConstants;
import frc.robot.Constants.XboxControllerButtonMappings;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
public class DriveTrainSubsystem extends SubsystemBase {
// A whole lot of motors.
// First letter is which side of the drive train
// motor is on, looking from the side of the intake.
// Second letter is which of the three, T is top,
// F is front, where the shooter is ; B is back where the intake is.
// Master motors
WPI_TalonFX LT = new WPI_TalonFX(DriveConstants.LTFalconID);
WPI_TalonFX RT = new WPI_TalonFX(DriveConstants.RTFalconID);
// Follower motors
WPI_TalonFX LF = new WPI_TalonFX(DriveConstants.LFFalconID);
WPI_TalonFX LB = new WPI_TalonFX(DriveConstants.LBFalconID);
WPI_TalonFX RF = new WPI_TalonFX(DriveConstants.RFFalconID);
WPI_TalonFX RB = new WPI_TalonFX(DriveConstants.RBFalconID);
DifferentialDrive _drive = new DifferentialDrive(LT, RT);
private double speedMod = 0.5;
public DriveTrainSubsystem() {
LT.configFactoryDefault();
LF.configFactoryDefault();
LB.configFactoryDefault();
RT.configFactoryDefault();
RF.configFactoryDefault();
RB.configFactoryDefault();
LF.follow(LT);
LB.follow(LT);
RF.follow(RT);
RB.follow(RT);
LT.setInverted(true);
RT.setInverted(false);
LF.setInverted(false);
LB.setInverted(false);
RF.setInverted(true);
RB.setInverted(true);
//Config neutral deadband to be the smallest possible
LT.configNeutralDeadband(0.001);
RT.configNeutralDeadband(0.001);
/* Config the peak and nominal outputs */
LT.configNominalOutputForward(0, 30);
LT.configNominalOutputReverse(0, 30);
LT.configPeakOutputForward(1, 30);
LT.configPeakOutputReverse(-1, 30);
RT.configNominalOutputForward(0, 30);
RT.configNominalOutputReverse(0, 30);
RT.configPeakOutputForward(1, 30);
RT.configPeakOutputReverse(-1, 30);
/* Config the Velocity closed loop gains in slot0 */
LT.config_kF(0, DriveConstants.kFFvelocity, 30);
LT.config_kP(0, DriveConstants.kPvelocity, 30);
LT.config_kI(0, 0, 30);
LT.config_kD(0, 0, 30);
}
public void arcadeDrive(double speed, double rotation) {
_drive.arcadeDrive(-speed * speedMod, rotation * 0.5);
}
// Reusable method for setting different robot speeds.
public void changeSpeed(double s) {
speedMod = s;
}
}