-
Notifications
You must be signed in to change notification settings - Fork 0
Command based Programming 101
The 2019-DeepSpace project will utilize the Command-based Robot template, provided by the WPILib APIs, to program our 2019 robot. Understanding the following information will help with creating/editing subsystems and commands, which is the bulk of FRC programming.
The file (and subdirectory) structure organizes the code into logical areas to help us find and edit the parts we are interested in, whether it be to add a new command or to tune our PID constants. The file structure will resemble something like below:
<toplevel>/
commands/
TankDrive.java
IntakeSet.java
...
lib/
LogitechController.java
...
subsystems/
DriveTrain.java
Intake.java
...
util/
Constants.java
...
Main.java
OI.java
Robot.java
RobotMap.java
These files are the foundation of how the code runs.
-
Main.java- Starts the robot code -
OI.java- Contains any code relating to the Operator Interface- driverOI and operatorOI initialization
- button-to-port and axis-to-port mapping
- button-to-command mapping
-
Robot.java- Contains the code relating to the robot software lifecycle- subsystem initialization
- misc initialization (e.g., camera(s), dashboard, other processors like pigeon-board.)
- general periodic function (e.g., dashboard and other processor updates)
- auton (init and periodic functions)
- teleop (init and periodic functions)
- generally will run commands from the scheduler (explained further in "Scheduling Commands" subsection)
- test (init and periodic functions)
NOTE: We may further abstract out the code into two more top-level files,
Teleop.javaandAuton.javain future seasons. -
RobotMap.java- Contains the port numbering for various components (PWM, CAN, PCM12v, PCM24v, DIO, Analog)
-
subsystem/- Each subsystem maps to a major physical subsystem on the robot- component(s) initialization with proper
RobotMap.javaport numbering - should be "private" in scope - initialDefaultCommand() setup (if necessary - typically only
DriveTrain.javais expected to use this) - low-level function(s) which operate on component(s) and exposes functionality to higher-level
commands/- should be "public" in scope
- component(s) initialization with proper
-
commands/- Each command is a single function which operates on a subsystem (typically named likeIntakeSet.java- as long as each command is easily identifiable to a subsystem)-
initialize()- Called only once per command object instantiation (for setup) -
execute()- Called on every command call (typically on OI-mapped button.pressed()or.released()) -
isFinished()- Called after everyexecute()and a return ofFalsewill return the command back into the scheduler's command queue -
end()- Called after anisFinished()call returns True (for cleanup) -
interrupted()- Called when another command which requires the same subsystem is scheduled to run (if any)
-
-
util/- Utilities used by any other code are located here- Constants.java - All "magic numbers" will be stored here (to minimize hardcoded values directly in code for better readability)
-
lib/- Libraries used by certain related pieces of code are located here (e.g., all our OI port-mapping to buttons for different controllers likeLogitech,FightStick, orXbox- which are used only by the DriveTrain subsystem)
Most of the code is run as a First-In-First-Out (FIFO) queue where commands are added to the Scheduler's command queue. When the robot starts (via Main.java), it runs various initialization and periodic functions (via Robot.java) based on the "phase" given by FMS. Periodic functions are called every ~20ms and typically, the scheduler is called within these periodic functions via Scheduler.getInstance().run();. When buttons (mapped to commands in OI.java) are triggered, it will add those commands to the scheduler's command queue for future execution.
The first commands that are scheduled are any commands specified in the initializeDefaultCommand() for each subsystem. Typically, we expect only the DriveTrain subsystem to specify this since we want to immediately start driving. We also specifically set the DriveTrain's default command to always return False in its isFinished() function so that we can continue to drive, especially when no other commands are queued.
It's important that the scheduler's command queue becomes empty at each phases' initialization function.
Ping Peter Vu on Slack and he'll add any common questions to this section for others to read.