Creating Basic Commands Lesson

Creating Basic Commands: What the Robot Does

In the Command-Based framework, a Command is a single, reusable action that your robot can perform. It's a verb: `IntakeGamePiece`, `ShootNote`, `DriveForward`. Commands are the building blocks of all your robot's behaviors.

The Anatomy of a Command

A command's job is to define a sequence of steps to accomplish a specific task. Every command in WPILib has four core "lifecycle" methods that the Command Scheduler calls automatically at the right times.

The Command Lifecycle

  • `initialize()`: Called once when the command starts. Perfect for one-time setup like resetting an encoder.
  • `execute()`: Called repeatedly (every 20ms) as long as the command is running. This is where you put your main, continuous logic.
  • `isFinished()`: Called repeatedly. When this method returns `true`, the command ends.
  • `end(boolean interrupted)`: Called once when the command finishes (or is interrupted). Used for cleanup, like stopping motors.

Creating Your First Command: Drive with Joysticks

Let's create a basic command that makes the robot's drivetrain move using joystick input. First, we need a simple `DriveSubsystem` for the command to use.

Step 1: The `DriveSubsystem` (for context)

public class DriveSubsystem extends SubsystemBase {
    private final Spark m_leftMotor = new Spark(0);
    private final Spark m_rightMotor = new Spark(1);

    public void drive(double leftSpeed, double rightSpeed) {
        m_leftMotor.set(leftSpeed);
        m_rightMotor.set(rightSpeed);
    }

    public void stop() {
        drive(0, 0);
    }
}
    

Step 2: The `DriveWithJoysticks` Command

This command will take the `DriveSubsystem` and a `Joystick` as dependencies. It will continuously read the joystick's axes and command the drivetrain to move.

public class DriveWithJoysticks extends Command {
    private final DriveSubsystem m_drive;
    private final Joystick m_joystick;

    public DriveWithJoysticks(DriveSubsystem drive, Joystick joystick) {
        m_drive = drive;
        m_joystick = joystick;
        // A command MUST require any subsystems it uses.
        addRequirements(m_drive);
    }

    // Called every 20ms. This is the main logic loop.
    @Override
    public void execute() {
        double forwardSpeed = -m_joystick.getY();
        double turnSpeed = m_joystick.getX();
        
        // This is a simplified arcade drive logic
        m_drive.drive(forwardSpeed + turnSpeed, forwardSpeed - turnSpeed);
    }

    // This command should run forever, so it never "finishes".
    @Override
    public boolean isFinished() {
        return false;
    }

    // Called when the command ends.
    @Override
    public void end(boolean interrupted) {
        m_drive.stop(); // Stop the motors for safety.
    }
}
    

Test Your Knowledge

Question: In a command that reads a joystick to control a motor, which lifecycle method would contain the code `m_motor.set(m_joystick.getY())`?