How would the private final Subsystem be used in this case?

As seen in the picture below…

The once example subsystem is not used anywhere else in the command.java file. I also see that the constructor basically reassigns a string into a string and requires that string? I don’t see how the string is used. I would have thought that the private final would be used by this string but apparently not. Sorry for the wordy or confusing answer, just very confused with this new command based framework.

It’s not a string, it’s a DriveTrainSubsystem object. Just to clear that up.

This is a pattern called dependency-injection. The subsystem is injected through the command constructor.

You should read through the relevant command-based documentation, which will help better-understand what’s going on.

1 Like

I read through most of it and it doesn’t seem to help. Unless I’m reading it wrong it’s not very helpful with the coding side of it.

It’s not being used by anything though so I don’t know why the template created it.

In a command where you plan to drive the robot, you probably would need a drive subsystem to use. The constructor here saves whatever drive subsystem was inputted, and saves it for later as driveTrainSubsystem for use internally, so that when you write your execute() (the part that actually runs what you want the command to do), you won’t have to keep going back and referencing the one from Robot.java or wherever it happens to be.

Instead of in the old command based system where you would do Robot... Now you use whatever you named the object of the subsystem, in this case driveTrainSubsystem. So for a full Code it would be something like driveTrainSubstem.manualDrive(parse through inputs);

  • As for the inputs, I use a double supplier. So I would create two double suppliers. I can link code if you need help with that.

Our github is here:

Feel free and check out all the code, but specifically with regard to the command being constructed the final modifier it’s summed up like this:
Declare the reference types that you know the command is going to need with the final modifier such that they can only be set in the constructor.
Create a constructor that requires the dependencies for the command to work at runtime as arguments to the constructor (Dependency Injection).
Then, in the normal command scheduling loops (initialize, execute, etc) use the subsystems as they were meant to be used.

The link I gave you was a starting point for a default drive train command that will be used during teleop.

Hmm, you are adding the controller inside of the command? I don’t suggest doing this really. Look at the gearsbot demo and look at how they did it. You should only initialize the controller once inside the robot container.

Java passes objects by “value” which is the location, which is really pass-by-reference. The controller is only being initialized once in the robot container. The reference to that instantiated object is being passed and assigned to the DefaultDriveCommand, such that it is using the one singular controller that was instantiated in the container.

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 Doubles 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
));
1 Like

I think @djp0915’s message was in relation to the OP’s attached image, where they are initializing an XboxController object in their Command. Just accidentally set the reply to your message instead.

Yeah, reply was my post which confused me thinking it was talking about our code I posted as an example.

I misunderstood. I’ll leave the explanation for posterity in case anyone finds it useful.

Yep, whoops! My mistakes for replying to yours.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.