1 of 22

FRC COMMAND PATTERN

Falkon Robotics Team 589

2020 Season

Steve Gustafson – Senior Mentor

2 of 22

WHAT’S IN THIS PRESENTATION

  • This presentation is an introduction to the 2020 FRC command pattern, which has significant changes from prior years
  • The three main aspects of the command pattern are explained
    • Subsystems
    • Commands
    • User controls, or HID (Human Interface Devices, such as Joysticks)
  • Where and how the subsystems, commands, and controls are joined together to make functioning robot code

The command pattern is an industry recognized software architecture which is widely used as an extensible framework. It is one of many design patterns currently used by software professionals. Like all patterns, it is essential that coding is done consistent with the design of the framework.

If you’re not sure how and where your code fits in, ask for help.

3 of 22

INTRODUCTION

  • This presentation is divided into three sections:
    • Introduction (this section)
    • Starting up the Visual Studio Code example
    • Detailed explanation of the example code

4 of 22

INTRODUCTION CONTINUED

  • Visual Studio Code 2020 for FRC includes many examples
  • This presentation is based on the “Traditional Hatch Example”
  • Text and screenshots are taken from

5 of 22

THIS PRESENTATION IS BASED ON AN EXAMPLE

This presentation uses an example which comes with this year’s FRC extensions to Visual Studio Code

The example appears to have been developed before the 2020 re-write of the FRC command framework was complete

Except where otherwise noted, the code presented here complies with the final release version

6 of 22

  • Opening the Example Project

7 of 22

START VS CODE 2020

  • #1 Press the Windows key and type “vs code”
  • #2 Select VS Code 2020

Visual Studio Code has been extended with features specifically required for developing FRC code.

8 of 22

CREATE THE EXAMPLE PROJECT

  • Click on the “W” in the upper right
  • When the command list pops up, type “create”
  • Select “WPILib: Create a new project

9 of 22

CREATING THE HATCHBOT EXAMPLE

  • #3 Select a project base
  • #4 Select “Traditional Hatchbot
  • #1 Select “example”
  • #2 Select “java”

Complete filling out the page and be sure to enter “589” for the team number

10 of 22

WHERE THE FILES ARE - SUBSYSTEMS

  • Subsystems are where you start
    • HatchSubsystem.java in this example
  • Data member objects mirror the physical actuators and sensors that comprise the subsystem
  • Public methods (functions) are called by Command objects (discussed later)
  • Subsystem names are suffixed with “Subsystem

“Subsystems are the basic unit of robot organization in the command-based paradigm. A subsystem is an abstraction for a collection of robot hardware that operates together as a unit.”

11 of 22

Section 3

Code Annotations and Explanations

12 of 22

WHAT A SUBSYSTEM CONTAINS

  • #1 Java class library “imports”
  • #2 Subsystem class declaration
    • derives from “SubsystemBase
    • class member declarations and instantiations
  • #3 Public method to “grab” the hatch
  • #4 Public method to “release” the hatch

Public methods (#3 and #4) are simple methods that perform basic subsystem functions and are called by commands.

All subsystem java files will start with

“package frc.robot.subsystem” (line 8)

13 of 22

WHERE THE COMMANDS ARE

  • Command files are put into the “commands” folder
    • E.g., GrabHatch.java
  • Command class files are not suffixed with “Command”
  • Command class names are of the form “verb” + “noun”,
    • The “verb” is the action they perform
    • The “noun” is the subsystem they are commanding (without the “Subsystem” suffix)
    • Verb + Noun = “Grab” + “Hatch” equals “GrabHatch

14 of 22

VERY SIMPLE COMMAND CLASS – GRAB HATCH

  • #1 Imports the subsystem that this command is associated with
  • #2 The command class is defined by deriving from CommandBase
  • #3 A private class member for the subsystem is defined
  • #4 A constructor is defined which takes (at a minimum) a reference to the subsystem instance and calls “addRequirements(…)”, passing it the subsystem instance
  • #5 Overrides the “initialize()” method from CommandBase
  • #6 Overrides the “isFinished()” method from CommandBase

15 of 22

VERY SIMPLE COMMAND CLASS (CONTINUED)

  • A command class overrides methods in its base class (CommandBase)
  • These methods are called by a “hidden” command scheduler which runs every 20 milliseconds (50 times/sec)
  • The scheduler examines the state of joystick buttons and decide which commands need to be executed
  • In this case, when the button that has been bound to this command is pressed, the scheduler finds the associated command object and…
    • 1) Calls the “initialize()” method of the command object
    • 2) Checks to see if the command is finished (calls “isFinished()”), and if so, calls the “end()” method. Since this command does not override “end()”, the base class “end()” is called, which simply returns.

This example is simple because the hatch subsystem contains only a pneumatic solenoid. Solenoids instantaneously open or close. There is no “in between” state, so all that needs to be done for “grabHatch()” is to open the forward air valve to extend the hatch. This only needs to be done once per button press. For this reason, we can do all the work in the “initialize() method. “isFinished()” can simply return “true” because the valve is now open. Motors are different and usually require more methods to be overridden.

16 of 22

KEY THING TO KEEP IN MIND – NO LOOPS!

  • Nowhere in your code should you use any kind of loop
    • No “for…” loops
    • No “while…” loops
  • Why?
    • Your code executes inside the Scheduler loop!
    • Any ongoing action that a subsystem performs is coded in the “execute()” method of a command
    • The Scheduler keeps calling “execute()” in its own loop (50 times/sec) so you don’t have to (and MUST NOT) use a loop
    • One more thing…
      • DO NOT use any kind of “delay” or “sleep” function either (unless you really know what you’re doing)

17 of 22

WHERE BUTTONS, COMMANDS, AND SUBSYSTEMS COME TOGETHER

  • Where are the subsystem instances?
  • Where are the command instances?
  • Where do joystick buttons get bound to commands?

It all happens in RobotContainer.java

RobotContainer.java is often a pretty large file (it grows as commands and subsystems are added). It’s organized into well defined sections where specific kinds of things are done. Typically small groups of students are assigned to subsystems and their related commands, so there shouldn’t be issues accidently deleting/modifying other peoples work. But everyone will need to do some additions and changes to RobotContainer.java. Be careful to put your code in the right sections and not to modify other peoples code unless you coordinate with them!

We’ve seen where the subsystem and command classes are, but:

18 of 22

A FIRST LOOK INSIDE THE ROBOT CONTAINER

  • #1 Imports of classes that we don’t write
  • #2 Imports of our command and subsystem classes
  • #3 The RobotContainer class is defined
  • #4 Each of our subsystems is defined as“private final” members of the RobotContainer class. The members are instantiated where they’re defined

Note: Follow standard FRC Java guidelines and prefix class member names with “m_” (even if that is not your personal preference.) Adherence to coding standards is essential when developing code as a team.

19 of 22

INSIDE ROBOT CONTAINER – AUTONOMOUS AND DEFAULT COMMAND INSTANTIATION

[a] m_simpleAuto is declared as “Command” type and instantiates the “DriveDistance” command

[b] m_complexAuto is instantiated as the “ComplexAuto” command

[c] m_driverController in this example is an Xbox controller. We will use joysticks (very little code difference).

The m_chooser object is used to make autonomous commands available for selection in the Driver Station

20 of 22

CONTINUING WITH THE ROBOT CONTAINER – ROBOT CONTAINER CONSTRUCTOR

#1 Calls private method to bind buttons to commands

#2 Establishes a “default command” for the robot drive subsystem. (Default commands keep executing when no other command for its associated subsystem is executing)

#3 Passes a reference to m_robotDrive, and uses Java “Lambda” syntax to pass in two Java statements (we may decide not to do it this way)

#4 Adds two commands to the Driver Station autonomous chooser

#5 Puts the chooser (and its commands) on the dashboard

Notice the effective use of comments and well chosen names.

21 of 22

ROBOT CONTAINER - ESTABLISHING BUTTON BINDINGS (ROBOTCONTAINER.JAVA FILE)

For each button that will issue a command, a JoystickButton is instantiated. Its constructor is passed an instance of a driver control device (aka, Joystick)along with a constant identifying a specific button (line 90). Notice that a method on the newly instantiated instance is then called (such as in line 91. “.whenPressed(..)”), passing a “new” instance of command created by invoking the command’s constructor and passing in an instance of the command’s related subsystem. The subsystem instance is a member of the RobotContainer class.

There’s a lot going on in lines 90 and 91! This could be more easily understood by breaking these lines into more statements and not jamming them all together like this. It is not necessary to fully understand this – you can just follow examples.

The letters in boxes, [a], etc., show a correspondence between the command classes and the files that contain them.

Notice that both [a] and [b] use .whenPressed(..) but [c] uses .whenHeld(..). There are many variations.

22 of 22

POSSIBLE FUTURE ADDITIONS TO THIS PRESENTATION

  • Ideas for future presentations?
    • In depth exploration of how the Scheduler works
    • Detailed analysis of a Motor-based subsystem
    • Use of GIT and GitHub for source control
    • Debugging and Diagnostics