So, one of the big reasons for the re-write was to include some more modern development best practices. One of these is a concept called Dependency Injection. This is where any external resources required for a class are passed via the constructor or a method, rather than the coupling the class to the one containing the resource by accessing the external resource directly.
So, by their nature, a Command requires a Subsystem, thus you will need to pass in a Subsystem Object. In the case of most Drive Systems you will also need your Joystick Input. The simple way to do this is to pass in a GenericHID or Joystick object, the more advanced way (and one shown in the example project) is to use Lambda Functions to pass in the Joystick Axis Values themselves.
From the Gearsbot Example: https://github.com/wpilibsuite/allwpilib/tree/master/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/gearsbot
The TankDrive Command constructor takes in three Dependencies, the Subsystem the Command uses, and two Double
s which are the driving values, but of course you don’t want those values only once, but we also don’t need the who joystick, so we can use this fancy DoubleSupplier
object to say “give me a method that will give me a double value for X”. This is what I was talking about with lambda functions as you will see later. We then take these dependancies and store them in local fields so we can use them later in the command.
public TankDrive(DoubleSupplier left, DoubleSupplier right, DriveTrain drivetrain) {
m_drivetrain = drivetrain;
m_left = left;
m_right = right;
addRequirements(m_drivetrain);
}
Here, we use our passed-in subsystem object to perform our driving, utilizing the doubles
from the passed-in DoubleSupplier
objects. All this without having to go and grab things directly from the RobotContainer.
public void execute() {
m_drivetrain.drive(m_left.getAsDouble(), m_right.getAsDouble());
}
So how does this look from the top? Well, in RobotContainer, when we set the DefaultCommand for the Drivetrain subsystem, we pass in our Command’s dependencies. You’ll notice some weird syntax where we are getting the joystick axis values, well these are our Lambda functions, so instead of called getY()
once, we create a sort of anonymous function that is technically a DoubleSupplier
that can call it whenever we need the current value of the getY()
function later and pass all that to the Command, instead of what most teams did before by creating methods in the OI Class to getDriveLeftY()
and getDriveRightY()
or similar names that returned the values from the Joysticks.
m_drivetrain.setDefaultCommand(new TankDrive(
() -> m_joystick.getY(Hand.kLeft),
() -> m_joystick.getY(Hand.kRight),
m_drivetrain
));