Now that we have a DriveSubsystem to control the motors we are going to want to do something with it. In this programming model we use commands to control actions. In this chapter we are going to create a command which will cause the robot to drive forward for a specific amount of time.

You can think of commands as being a little like the following loop:

In fact, it’s more complicated, because these calls will be interleaved with other periodic commands, but that’s the basic idea. We do things this way to allow many such loops to run at the same time.

The first step is to create the new class called DriveForTimeCommand under the commands folder. Like we did with the DriveSubsystem, copy the ExampleCommand and paste it into the commands folder. Then change the name of the copy to and in that file search and replace all instances of ExampleCommand with DriveForTimeCommand. Also, since this command will be using the DriveSubsystem, replace all instances of ExampleSubsystem with DriveSubsystem. Also you should change the comment describing the purpose of this command (i.e. “An example command that uses an example subsystem”) to one that describes this command. After you have done that you file should look like:

Let’s take a look at the constructor:

The first thing we need to do is to save a copy of the DriveSubsystem instance that we are passing into the member variable m_subsystem so that we have access to it later. Second, it is here that we will specify which Subsystems this command will require. We do this by calling the addRequirements(…) passing in the DriveSubsystem instance we just saved. It is important this we do this because this is how the command system keeps track of which commands need which subsystems and makes sure that only one command at a time has access to a particular subsystem. If we get this wrong, we might end up with mysterious problems where two commands are fighting for control of the same motor.

The next function initialize() is called whenever this command starts. In our case, when the command runs we want to start the robot moving forward. Also we are going to want to have a timer to control how long the robot will drive and we will need to reset that timer when the command starts.

Of course we must also declare and initialize the variable m_timer at the top of our class.

Now you will also need to import the Timer class. This time when you click on Timer and press CTRL + ., you will see multiple possible choices. We want to choose the version from RobotCore:

The next function in our class, execute(), is called repeatedly as long as this command is running. Since we are simply going to continue driving until the timer expires, we don’t need to do anything special here.

Next there is the end() function which is called when a command ends. When this happens we want to turn the motors off:

Finally there is the isFinished() function. This function is also called repeatedly as long as the command is running, and should return false if it wants the command to continue, and true if it wants it to end. In our case, we want the command to end when the timer exceeds 2 seconds:

Your file should now look like:

Now we need to provide some way to run this command and we will do this by tying this command to a button on the joystick. The place to do this is in the RobotContainer class that we mentioned previously. Be sure to save your file and then open the file by clicking on it in the left pane.

Since we will be using the joystick, we need to create an instance of the Joystick class as well as an instance of the JoystickButton class. We are also going to need an instance of the DriveSubsystem so we declare that here as well. We do this by adding the following to the RobotContainer class:

The declaration of m_driveSubsystem creates an instance of our DriveSubsystem class.

The declaration of m_joystick creates an instance Joystick number 0. Our implementation of the Joystick class really only supports a single joystick, but the joystick number is included in the constructor to be consistent with the FRC library which supports multiple joysticks.

The declaration of m_button1 creates an instance of JoystickButton which ties it to the number 1 button on the joystick.

Now we need to connect the button we just declared to our DriveForTimeCommand. We will do this in the configureButtonBindings() function of the RobotContainer:

Here we create a instance of our DriveForTimeCommand, passing in our instance of the DriveSubsystem, and tell the JoystickButton class to call that instance when the button is pressed. This is an example of event-driven programming. We’re not checking the state of the button and then doing something; instead we’re defining something that should happen whenever the button is pressed.

Your file should now look like:

Now run your program (remember that if your program is already running, you need to stop it using the red stop button  ) and connect and enable your robot from the Driver Station. Since you don’t have an actual joystick attached to your computer, click the Enable Virtual Joystick checkbox which will allow you to use a simulated joystick.

With your robot enabled, click the B1 button and your robot should drive forward for 2 seconds (make sure you put your robot on the floor!)

Before we move on, let’s try and make this command more useful. Right now it is always driving the robot at 75% power, and always for 2 seconds. We would like to change this command so that we can control both the time and the speed.

The place to set these values is when we call the constructor for the class. We add two parameters power and time to the constructor and add two member variables m_power and m_time to store these values:

Now in our initialize() function we need to run the robot at the specified m_power:

Finally, we need to change our isFinished() function to use the specified m_time:

Your file should now look like:

You will no notice that your RobotContainer class now has an error on the line where we create an instance of DriveForTimeCommand. Hovering over the error marker it tells us:

The reason it is telling us this is that there is no longer a constructor for this class that takes only one argument (remember that we changed the constructor). So what we must do is provide the proper arguments for the new constructor. Lets have our robot drive forward at 0.50 power for 3 seconds:

Now deploy and run your program that the robot now drives at half power for three seconds.

You might notice that your robot is not driving quite straight but don’t worry, we will address this issue later.

Next: Arcade Drive