Changes between Version 10 and Version 11 of ControlSystems/SoftwareTeam/Training/WPILib/CommandBasedProgramming


Ignore:
Timestamp:
Feb 23, 2020, 3:30:44 PM (5 years ago)
Author:
David Albert
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • ControlSystems/SoftwareTeam/Training/WPILib/CommandBasedProgramming

    v10 v11  
    1111=== Creating a Command-Based Program ===
    1212Create a new project in VSCode (WPILib Icon->Create a new project->Template->Java->Command Robot).  Notice that in the project src folder, addition to the Main.java and Robot.java we're used to seeing, the project also has: [[Image(CommandBasedFiles.jpg,align=right,margin=10)]]
    13    * OI.java - where the Operator Interface is defined
    14    * !RobotMap.java - where global constants are defined (e.g. motor controller addresses)
     13   * RobotContainer.java - where the subsystems, commands, and button bindings are defined
     14   * Constants.java - where global constants are defined (e.g. motor controller addresses) - may be called !RobotMap
    1515   * commands folder - where your Commands will be stored
    1616   * subsystems folder - where your Subsystems will be stored
    17 Robot.java still extends !TimedRobot (the framework we've been using until now) and the methods robotInit(), robotPeriodic(), autonomousInit(), autonomousPeriodic(), teleopInit(), teleopPeriodic().  However, it now includes an example subsystem and an instance of the OI (Operator Interface) that represents the driver station; the OI helps bind the controls on the driver station (e.g. joystick, xbox controller) to the activities (commands, command groups) that your robot will be performing.  For example, the OI allows you to connect a button on your controller to an activity like launching a frisbee.
     17Robot.java still extends !TimedRobot (the framework we've been using until now) and the methods robotInit(), robotPeriodic(), autonomousInit(), autonomousPeriodic(), teleopInit(), teleopPeriodic().  However, it now creates and instance of the !RobotContainer class that creates the robot subsystems, user interface objects(xbox controller, joysticks, etc.) and binds button presses to the activities (commands, command groups) that your robot will be performing.  For example, when the X button is pressed on your controller run a command to launch a frisbee.
    1818
    1919=== Example Code ===
     
    2222The following is an example of a very simple Command Based Robot that has a single subsystem consisting of a servo motor with two positions: Open, Closed and they are selected using the A and B buttons on a gamepad.  The servo motor should be connected to PWM port 0 and the code uses a Logitech F310 for the operator interface.  Replace the template files with:
    2323
    24 !RobotMap.java:
     24Constants.java:
    2525{{{
    2626package frc.robot;
    27 public class RobotMap {
    28   public static int SERVO_PORT = 0;   // PWM port for servo motor
    29   public static int OPEN_BUTTON = 1;  // A button opens mechanism
    30   public static int CLOSE_BUTTON = 2; // B button closes mechanism
     27
     28public final class Constants {
     29    public static int SERVO_PORT = 0;   // PWM port for servo motor
     30    public static int OPEN_BUTTON = 1;  // A button opens mechanism
     31    public static int CLOSE_BUTTON = 2; // B button closes mechanism   
    3132}
    3233}}}
     
    3637package frc.robot.subsystems;
    3738
    38 import edu.wpi.first.wpilibj.command.Subsystem;
    39 import frc.robot.RobotMap;
     39import edu.wpi.first.wpilibj2.command.SubsystemBase;
     40import frc.robot.Constants;
    4041import edu.wpi.first.wpilibj.Servo;
    4142
    42 public class ServoSubsystem extends Subsystem {
     43public class ServoSubsystem extends SubsystemBase {
    4344  private Servo servo;
    4445
     
    4647
    4748  private ServoSubsystem() {
    48       servo = new Servo(RobotMap.SERVO_PORT);
     49      servo = new Servo(Constants.SERVO_PORT);
    4950  }
    5051
     
    5960  public void setAngle(double degrees) {
    6061    servo.setAngle(degrees);
    61   }
    62 
    63   @Override
    64   public void initDefaultCommand() {
    6562  }
    6663}
     
    9491package frc.robot.commands;
    9592
    96 import edu.wpi.first.wpilibj.command.Command;
    97 import frc.robot.Robot;
     93import edu.wpi.first.wpilibj2.command.CommandBase;
     94import edu.wpi.first.wpilibj2.command.SubsystemBase;
     95import frc.robot.subsystems.ServoSubsystem;
    9896
    99 public class CloseCommand extends Command {
    100   public CloseCommand() {
    101     requires(Robot.m_servo); // servo must be available
    102   }
     97public class CloseCommand extends CommandBase {
    10398
    104   @Override
    105   protected boolean isFinished() {
    106     System.out.println("Close Pressed.");
    107     Robot.m_servo.setAngle(120); // set servo to closed position
    108     return true;                 // and then finish
    109   }
     99    public CloseCommand(SubsystemBase servoSubsystem) {
     100        addRequirements(servoSubsystem);
     101    }
     102
     103    @Override
     104    public boolean isFinished() {
     105        System.out.println("Close Pressed.");
     106        ServoSubsystem.getInstance().setAngle(120); // set servo to closed position
     107        return true;                 // and then finish
     108    }
    110109}
    111110}}}
    112111
    113 OI.java:
     112RobotContainer.java:
    114113{{{
    115114package frc.robot;
    116115
    117116import edu.wpi.first.wpilibj.XboxController;
    118 import edu.wpi.first.wpilibj.buttons.Button;
    119 import edu.wpi.first.wpilibj.buttons.JoystickButton;
    120 import frc.robot.RobotMap;
    121 import frc.robot.commands.*;
     117import edu.wpi.first.wpilibj2.command.button.Button;
     118import edu.wpi.first.wpilibj2.command.button.JoystickButton;
     119import edu.wpi.first.wpilibj2.command.Command;
     120import frc.robot.subsystems.ServoSubsystem;
     121import frc.robot.commands.OpenCommand;
     122import frc.robot.commands.CloseCommand;
    122123
    123 public class OI {
    124   XboxController xbox = new XboxController(0);
    125   Button openButton = new JoystickButton(xbox, RobotMap.OPEN_BUTTON);
    126   Button closeButton = new JoystickButton(xbox, RobotMap.CLOSE_BUTTON);
     124public class RobotContainer {
     125  private final ServoSubsystem m_servo = ServoSubsystem.getInstance();
     126  private final XboxController xbox;
     127  private final Button openButton, closeButton;
    127128
    128   public OI() {
    129     openButton.whenPressed(new OpenCommand());
    130     closeButton.whenPressed(new CloseCommand());
     129  public RobotContainer() {
     130    xbox = new XboxController(0);
     131    openButton = new JoystickButton(xbox, Constants.OPEN_BUTTON);
     132    closeButton = new JoystickButton(xbox, Constants.CLOSE_BUTTON);   
     133
     134    // Configure the button bindings
     135    configureButtonBindings();
     136  }
     137
     138  private void configureButtonBindings() {
     139    openButton.whenPressed(new OpenCommand(m_servo));
     140    closeButton.whenPressed(new CloseCommand(m_servo));
     141  }
     142
     143  public Command getAutonomousCommand() {
     144    return null;
    131145  }
    132146}
     
    138152
    139153import edu.wpi.first.wpilibj.TimedRobot;
    140 import edu.wpi.first.wpilibj.command.Scheduler;
    141 import frc.robot.subsystems.ServoSubsystem;
     154import edu.wpi.first.wpilibj2.command.CommandScheduler;
    142155
    143156public class Robot extends TimedRobot {
    144   public static ServoSubsystem m_servo = ServoSubsystem.getInstance();
    145   public static OI m_oi; // operator interface
     157  private RobotContainer m_robotContainer;
    146158
    147159  @Override
    148160  public void robotInit() {
    149     m_oi = new OI();
     161    m_robotContainer = new RobotContainer();
    150162  }
    151163
    152164  @Override
    153   public void disabledPeriodic() {
    154     Scheduler.getInstance().run(); // run enabled commands
    155   }
    156 
    157   @Override
    158   public void autonomousPeriodic() {
    159     Scheduler.getInstance().run(); // run enabled commands
    160   }
    161 
    162   @Override
    163   public void teleopPeriodic() {
    164     Scheduler.getInstance().run(); // run enabled commands
     165  public void robotPeriodic() {
     166    CommandScheduler.getInstance().run();
    165167  }
    166168}
     
    168170
    169171=== How it works ===
    170 Command-based programming is built on top of the !IterativeRobot template. In each of the template's periodic() methods, Scheduler.getInstance().run() is called. This takes all currently running Commands -- which behave like threads, but can't include waits like typical threads because it's a type of threading known as "cooperative" multitasking -- and runs them, first initializing any new ones and checking whether each one has completed yet. It's useful because these Commands can be easily joined together in CommandGroups to make autonomous modes, or can be mapped to buttons to easily allow complex teleop actions, etc.
     172Command-based programming is built on top of the !TimedRobot template. In each of the template's periodic() methods, !CommandScheduler.getInstance().run() is called. This takes all currently running Commands -- which behave like threads, but can't include waits like typical threads because it's a type of threading known as "cooperative" multitasking -- and runs them, first initializing any new ones and checking whether each one has completed yet. It's useful because these Commands can be easily joined together in CommandGroups to make autonomous modes, or can be mapped to buttons to easily allow complex teleop actions, etc.
    171173
    172174* [https://docs.google.com/document/d/1JHHRGrhe96rJXw6lIM-X3WJKoD14_8PwqjjP45UI0tg/ Intro to Command Based Programming]