You are on page 1of 9

C++

Command
Based
Frogramming
Guide

Fightin’ Robotic Owls 5401 Page 1 of 9


Abstract: Command-based architecture is the recommended architecture for a mature FRC
team to develop code for its robot, and used by some of the most successful FRC teams. It
has several advantages over simple or iterative code; it is very modular, permitting easy
change out of sections of code, debugging, reuse from one project to the next, and division
of responsibility among multiple (student) developers. The Command-based architecture
divides the robot code into 3 categories: Subsystems, Commands, and Triggers. Subsystems
contain all the physical movers and the functions which can be performed by them.
Commands invoke these Subsystems and pass parameters to the functions. Triggers the
tutorial says nothing about and the few examples are impenetrable so TBD.

Purpose: This guide is intended to lay out the basic needs of programming within the
Command Based architecture for someone with a rudimentary understanding of C++
programming.

Scope: This guide covers only the intricacies of working within the Command-based
architecture of C++ FRC programming. It is not intended to provide information on C++
programming in general or introduce programming concepts. It should be viewed in the
context of sample code such as the FRC provided GearsBot code or at a minimum the
template structure provided with the FRC libraries and resources, as the examples here are
limited to very short (1-5 lines) samples of code to demonstrate a specific concept.

1. Subsystems
Subsystems are groups of components, and the functions associated with them. Each
subsystem gets a .h file and a .cpp file. You should expect to jump back and forth between
these two files while developing the subsystem. “ExSubsystem” is used as the name of a
hypothetical subsystem throughout.
1.1. ExSubsystem.h
1.1.1. Define TBD
1.1.2. Includes
Note the Subsystem.h is exactly that, not to be confused with ExSubsystem. Also worth
noting that while this include appears in the template and sample code of several teams,
the actual file is nowhere to be found.
Commands/Subsystem.h
WPILib.h

1.1.3. Controller declaration


1.1.3.1. Private
Sample files indicate that everything possible should be kept under private, except
for methods that implement subsystem capabilities. Not sure what this means, or
what things belong here. Expect this section of the Guide to be updated as
appropriate material is discovered.
1.1.3.2. Public
Each of the actuator controllers used by the subsystem should be declared, as a
pointer.
Ex.
Talon *LeftDriveMotor;
Victor *RightDriveMotor;
An overview of the available actuators:

Fightin’ Robotic Owls 5401 Page 2 of 9


1.1.4. Function Prototypes
Each of the functions used in the Subsystem.cpp file should be declared here. First should
be the constructor with the same name as the subsystem. Each Prototype should be of
the form function(type, type,...). Hypothetically, functions can be overloaded, but this has not
been attempted.
1.2. ExSubsystem.cpp
1.2.1. Declarations
Each controller used in the subsystem should be declared using the name of the pointer
and a channel number that is defined in RobotMap.h. Ex.
LeftDriveMotor = new Talon(LeftDriveMotorChannel);
RightDriveMotor = new Victor(RightDriveMotorChannel);
See RobotMap.h for info on defining channels as constants.

1.2.2. Code
1.2.2.1. Default Command
Each of the functions of the subsystem are coded here. Subsystems may have an
“InitDefaultCommand”, which is the default command to operate on this subsystem.
For example, a drive train may have a default driving mode (as opposed to a
braking mode or precision mode). This is initiated by:
setDefaultCommand(new ExCommand());
Where ExCommand is the desired default command. This will run whenever the
subsystem is otherwise idle, i.e. no other commands are using the subsystem. May
subsystems will not have a default command, and the method can simply contain no
code for this (commenting is recommended).
A Drive subsystem will always have a default. This should be the controller
movement command.

1.2.2.2. Other Functions


Other methods that this subsystem can perform are specified here. In a drive system,
for example, there may be methods for how to drive in autonomous mode, in
precision mode, or a brake method.

1.3. Supporting Files


The following files must be updated to include every subsystem. See their individual sections
for details:
CommandBase.h
CommandBase.cpp
RobotMap.h
Fightin’ Robotic Owls 5401 Page 3 of 9
2. Developing Commands
TBD
2.1. ExCommand.h
2.1.1. Define TBD
2.1.2. Includes
../CommandBase.h
WPILib.h
Note: CommandBase include should reflect directory structure. “..” indicates go one
directory up.

2.1.3. Code
2.1.3.1. Declarations
N/A?
2.1.3.2. Prototypes
The following prototypes exist for every command. Each of these is explained in the
ExCommand.cpp section. These should all be declared with their proper parameter
types in the header file.
Constructor(type, type…) //method with the name of the command
Initialize(type, type…)
Execute(type, type…)
IsFinished(type, type) //always a Boolean function, see 2.2.2.2.4
End(type, type…)
Interrupted(type, type…)

2.2. ExCommand.cpp
2.2.1. Includes
ExCommand.h
2.2.2. Code
2.2.2.1. Declarations
2.2.2.2. Methods
2.2.2.2.1. ExCommand() //Constructor for the class
Constructor must include a Requires statement for each subsystem that will be
used by the class. This reserves that subsystem for the command and interrupts
any other command using the subsystem (invoking the other command’s
Interrupted method). Ex.
Requires(exsubsystem);
Note the subsystem reference is the initialized static version created in
CommandBase.cpp. See that section (3.2.2.2.2) for information on this
initialization.

2.2.2.2.2. Initialize

Fightin’ Robotic Owls 5401 Page 4 of 9


This method is called before ExCommand runs for the first time. May be blank for
some commands.

2.2.2.2.3. Execute
This method is what runs over and over again as long as ExCommand is
scheduled to run.

2.2.2.2.4. IsFinished
This is always a Boolean function and serves as a flag to tell the scheduler to
begin shutting down this command. Make this function return TRUE when the
command no longer needs to run. For a continuously running function, such as a
Drive command, this can be hard coded to never end, eg. return false;

2.2.2.2.5. End
This method is called once after IsFinished returns true and contains any actual
code for shutting down the command, e.g. any reset, possibly a subsequent
command to initialize.

2.2.2.2.6. Interrupted
This method is called when another scheduled command requires the same
subsystem.

2.3. Supporting Files


The following files must be updated to include every command. See their individual sections
for details:
OI.cpp

3. Developing Command Groups


Command Groups allow running groups of commands sequentially or in parallel. Each of
the commands run must have their own command in accordance with sec. 2.
3.1. ExCommandGroup.h
3.1.1. Define TBD
3.1.2. Includes
../CommandBase.h
WPILib.h
Note: CommandBase include should reflect directory structure. “..” indicates go one
directory up.

3.1.3. Code
3.1.3.1. Declarations
N/A?
3.1.3.2. Prototypes
Command Groups have only one function, and are the constructor for that class.
This should be declared with its proper parameter types in the header file.
Constructor(type, type…) //method with the name of the command group

3.2. ExCommandGroup.cpp

Fightin’ Robotic Owls 5401 Page 5 of 9


3.2.1. Includes
In addition to those listed below, each h file for every Command that the group will call
should be included here.
ExCommandGroup.h
3.2.2. Code
3.2.2.1. Declarations
3.2.2.2. Methods
3.2.2.2.1. ExCommandGroup() //Constructor for the class
Command Groups will only have a series of statements invoking the commands
that the
command group wants to execute. There are two commands that will be used:
AddSequential(new ExCommand());
AddParallel(new ExCommand());
Sequential commands will execute one after another. Parallel commands that
are listed together will execute together along with the sequential that immediately
follows them. E.g,
AddSequential(new ExCommand1());
AddParallel(new ExCommand2());
AddParallel(new ExCommand3());
AddSequential(new ExCommand4());
AddSequential(new ExCommand5());
Will execute ExCommand1, and then 2, 3, 4 all in parallel with each other, and
then 5.

4. Supporting Files
4.1. RobotMap.h
RobotMap is a file which only contains constants for each channel that joysticks, motor
controllers, sensors, pneumatics are plugged into. Constant integers are declared with
logical names. When the device is declared in the subsystem, the channel constant is used
as the parameter. This allows one stop shopping for reviewing and changing of device
channels.
4.1.1. Includes
WPILib.h
4.1.2. Code
Entire content of this file is a series of const int's. Comments are used to separate it into
sections. It is fairly simple and straightforward.

4.2. CommandBase
CommandBase stores and creates each subsystem. Every subsystem will be referenced
in the CommandBase header and code files.
4.2.1. CommandBase.h
4.2.1.1. Includes
Commandbase should include each and EVERY subsystem in the form:
#include “Subsystems/ExSubsystem.h”
where Subsystems is the directory containing the header file for the relevant
subsystem. If there is a deeper directory structure, that should be reflected in the
include (ex. Subsystems/Sensors/Encoders.h). As well as:
OI.h
WPILib.h

Fightin’ Robotic Owls 5401 Page 6 of 9


4.2.1.2. Code
4.2.1.2.1. Prototypes
Protypes for the CommandBase constructor (possibly overloaded) go here.

4.2.1.2.2. Declarations
CommandBase class declares each subsystem as a static with a pointer. The
pointer, in FRC examples, is the same name as the subsystem, except all lower
case. E.g.
static DriveBase *drivebase;

4.2.2. CommandBase.cpp
4.2.2.1. Includes
CommandBase.h
Scheduler.h

4.2.2.2. Code
4.2.2.2.1. Declarations
Each and every subsystem must be initialized. A single static instance should be
initialied to null. E.g.
ExSubsystem* ComandBase::exsubsystem = NULL;

4.2.2.2.2. Creation
Create a single static instance of each and every subsystem. E.g.
exsubsystem = new ExSubsystem();

4.3. OI
4.3.1. OI.h
4.3.1.1. Includes
WPILib.h
4.3.1.2. Code
4.3.1.2.1. Declarations
Each Joystick should be declared here as a pointer. Ex.
Joystick *LogitechStick;
Each button that should also be declared here as a pointer. Ex.
Button *LeftTrigger1;
4.3.1.2.2. Prototypes
Each function within the OI should be prototyped here, starting with a constructor
function named OI.
4.3.2. OI.cpp
4.3.2.1. Includes
In addition to those listed below, each h file for every Command that uses an OI
device should be included here.
OI.h
RobotMap.h
4.3.2.2. Code

Fightin’ Robotic Owls 5401 Page 7 of 9


4.3.2.2.1. Declarations
Each device is declared here, and assigned a channel from RobotMap. Ex:
Logitech3DPro = new Joystick(Logitech3D_Channel);
4.3.2.2.2. Button Definitions
This section assigns intuitive names to each button of the OI device, based on a
pointer array.
4.3.2.2.3. Functions
Functions involving the OI devices are defined here. For example, polling analog
inputs from a joystick require functions. These functions can be relatively simple,
just polling and then returning the value polled.
4.4. Robot.cpp
Robot.cpp is the main() of a command based architecture. It is generally fairly simple and
only kicks off the commands and subsystems that are described elsewhere in this document.
Most Teleop programming will do very little editing of Robot.cpp. Autonomous and
SmartDashboard programming will be the majority of what affects Robot.cpp in this section
at this time.
4.4.1. Includes
In addition to the includes below, each h file for every Command should be included
here.
WPILib.h
Command.h
CommandBase.h
4.4.2. Code
4.4.2.1. Declarations
4.4.2.1.1. Autonomous
Where Robot.cpp is being used to select an Autonomous mode, a pointer to a
place to store the command that will be called must be created. This will be in
the form of:
Command *autonomousCommand;

4.4.2.1.2. SmartDashboard
Where Robot.cpp is being used to call and establish SmartDashboard data,
pointers must be established for Live Window and any widgets that have code in
Robot.cpp. This will be in the form of:
LiveWindow *lw
SendableChooser *autoMode
Sendable Chooser is a SmartDashboard default type. Other types exist and will
be added/discussed in a later version of this document.

4.4.2.2. Methods
Most of the code in Robot.cpp is auto generated by the template when the files are
set up. This should only be edited by advanced users, and are not discussed in this
version of the document.
4.4.2.2.1. Autonomous
Fightin’ Robotic Owls 5401 Page 8 of 9
4.4.2.2.1.1. AutonomousInit()
This defines the command to execute when Autonomous mode is first
enabled. At this point of our development capability, this should call the
command or command group that will execute our Autonomous Mode code.
This will come in one of two forms:
ExCommand -> Start(); //This is your simple Call the Command or Command Group code.
Or
autonomousCommand -> Start(); //where autonomousCommand is the pointer declared above,
which has been assigned a function based on some logic or user input – see SmartDashboard
section below.
4.4.2.2.1.2. AutonomousPeriodic()
TBD – don’t mess with this at this time
4.4.2.2.2. SmartDashboard
A more complete discussion of the SmartDashboard will be completed in a later
version and in its own section of this document. This section is focused on using
the SmartDashboard to select an Autonomous Mode.
4.4.2.2.2.1. SendableChooser
SendableChooser is a class that presents a list of options to the Smart
Dashboard. The user declares an instance of it in the form of:
autoMode = new SendableChooser();
Once declared, the following functions are invoked to create options on the
list and assign a value to them.
autoMode -> AddDefault(“Option Name”, new ExCommand());//This option will be the default if
nothing is user-selected
autoMode -> AddObject(“Option Name”, new ExCommand());
4.4.2.2.2.2. GetSelected
autonomousCommand = (Command *) autoMode -> GetSelected();
This reads the selected value from the SendableChooser on the
SmartDashboard. You would write this value to a pointer before initiating the
command that was selected here. E.g.
autonomousCOmmand -> Start(); //actually executes the command, assuming the value in the
selection is a command like ExCommand()

5. Sensors
6. Smart Dashboard

Fightin’ Robotic Owls 5401 Page 9 of 9

You might also like