Example Java using DifferentialDrive (tank drive), for Falcon 500 controller

With the 2022 WpiLib, the DifferentialDrive class is constructed with two MotorControllerGroup objects. The MotorControllerGroup object is constructed using a MotorController class.
I believe the com.ctre.phoenix.motorcontrol.can.TalonFX is the correct class used as the controller for the Falcon 500, but it does not extend MotorController.
The example from ctre, use a WPI_TalonFX as a Motor Controller class, but this class also does not extend MotorController, rather it extends SpeedController, which is deprecated.

Does anyone have a Java example for a tank drive with Falcon 500 motors using 2022 wpilib?

What version of Phoenix vendordep are you using? The Phoenix javadocs show that WPI_TalonFX class does indeed extend MotorController: CTRE_Phoenix: com.ctre.phoenix.motorcontrol.can.WPI_TalonFX Class Reference

1 Like

Thanks, that was my issue. Latest version is correct.

I am having an issue as well. Would you mind sharing your code with me?

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() {

















    //Config neutral deadband to be the smallest possible



    /* 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;