-
Notifications
You must be signed in to change notification settings - Fork 1
High Level Overview
This overview explains the robot control system at the level needed to start reading and debugging team code. It is technical, but it is written for new software members who are still building their mental model of the robot.
The main idea is simple:
human input or autonomous routine
-> Driver Station mode and controller data
-> robot code running on the roboRIO
-> WPILib and vendor libraries
-> motor controllers, sensors, and actuators
-> physical robot behavior
-> sensor feedback, logs, and dashboards
-> robot code reacts again on the next loop
Every software task sits somewhere in that loop.
Passing a Java evaluation means you can write basic Java. It does not automatically mean you can work safely and effectively on robot code.
Robot software adds several layers:
- real hardware,
- robot lifecycle modes,
- motor controllers,
- sensors,
- electrical communication buses,
- mechanical constraints,
- driver controls,
- autonomous timing,
- logs and dashboards,
- code review and deployment workflow.
The training program is meant to build the ability to read an existing robot codebase and make scoped changes with evidence. A useful new software member should be able to:
- find the right file before editing,
- trace an input from controller or autonomous code to subsystem behavior,
- identify what hardware a line of code affects,
- use simulation when it is useful,
- use logs instead of guessing,
- explain what changed and how it was tested,
- avoid unsafe robot behavior during bringup.
The lessons are not just about syntax. They are about developing a control-systems debugging mindset.
Most robot behavior follows a repeated loop:
- The Driver Station sends the robot mode, enable state, and controller inputs to the robot.
- The roboRIO runs the robot program.
- The robot code reads controller state, sensors, and internal subsystem state.
- The code chooses commands, setpoints, or control requests.
- Vendor libraries and WPILib convert those requests into hardware commands.
- Motor controllers and actuators apply output.
- Sensors and motor controllers report what happened.
- Logs and dashboards expose the data.
- The next loop runs with updated information.
This loop normally runs many times per second. A bug can happen at any point in the loop.
When something does not work, do not ask only "what line is wrong?" Ask:
- Did the Driver Station send the expected mode and input?
- Did the code path run?
- Did the subsystem choose the expected goal?
- Did the motor controller receive the expected command?
- Did the sensor report a plausible value?
- Did the mechanism physically move as expected?
- Did the logs confirm the target, measurement, and output?
The Driver Station is the laptop-side control program used to communicate with and operate the robot.
The Driver Station does not run subsystem code. The robot code runs on the roboRIO. The Driver Station tells the roboRIO:
- whether the robot is enabled or disabled,
- which mode is active,
- what controller inputs are currently pressed or moved,
- match timing and field information during competition,
- alliance information when connected to the field.
The Driver Station is also one of the first debugging tools. It shows whether the robot is connected, whether robot code is running, whether joysticks are detected, and whether the robot is enabled.
The main robot modes are:
- Disabled
- Autonomous
- Teleop
- Test
Disabled means robot outputs should be safe. Code still runs, logs can still update, dashboards can still display data, and sensors can still be read. Disabled does not mean "nothing is happening in software." It means the robot should not be applying active motor output.
Autonomous means the robot runs preplanned behavior without normal driver joystick control. Autonomous code may still use sensors, pose estimation, timers, commands, and path-following libraries.
Teleop means driver and operator controls are active. Most controller bindings and default commands matter in teleop.
Test is used for explicit test behavior when configured. Do not assume test mode is safe unless you know what the current code does.
Enable state is safety-critical.
When disabled:
- motors should not be driven by normal commands,
- mechanisms should not start moving unexpectedly,
- it is safer to inspect the robot physically,
- code can still update internal state and logs.
When enabled:
- motor outputs can apply immediately,
- autonomous commands can move the robot,
- controller inputs can trigger mechanisms,
- mistakes become physical.
Before enabling, know:
- what code changed,
- what mode you are enabling,
- what command or default command will run,
- what controller inputs are active,
- who is ready to disable,
- whether the robot is physically safe.
If behavior is unexpected, disable first and debug afterward.
Controllers plug into the Driver Station laptop over USB. The Driver Station reads the axes and buttons, then sends that state to the roboRIO.
Code usually reads controller state through WPILib objects:
CommandXboxController driver = new CommandXboxController(0);In our codebase, controller mappings are usually centralized in a file like Controllers.java, and those triggers or axes are consumed in RobotContainer.java or subsystem logic.
The path is:
physical controller
-> USB to Driver Station laptop
-> Driver Station controller tab
-> robot packets to roboRIO
-> WPILib controller object
-> trigger, command, or subsystem code
If a button does nothing, check the whole path:
- Is the controller plugged in?
- Does the Driver Station see it?
- Is it in the expected port?
- Is the code reading the correct axis or button?
- Is the robot in the expected mode?
- Is the relevant command scheduled or code path running?
Do not start by changing subsystem logic until the input path is confirmed.
At competition, the Field Management System controls match timing and robot enable state. The field tells the Driver Station when the robot is disabled, autonomous, teleop, or ended.
This matters because code that seems fine in the lab may behave differently when:
- alliance color is supplied by the field,
- autonomous timing is controlled by the field,
- the robot is enabled by FMS instead of by a local practice setup,
- network conditions differ from the lab.
Do not hard-code assumptions that only work in a local test environment.
The roboRIO is the main robot controller. It is the computer on the robot that runs the Java robot program.
The roboRIO is responsible for:
- running deployed robot code,
- receiving Driver Station packets,
- tracking robot mode and enable state through WPILib,
- communicating with CAN devices,
- reading sensors connected directly to roboRIO ports,
- controlling PWM, digital, analog, relay, I2C, and SPI devices,
- exposing hardware interfaces to WPILib and vendor libraries.
Think of the roboRIO as the center of robot-side software. The Driver Station gives it control state. The roboRIO runs the program that decides what outputs should be applied.
When you deploy robot code:
local laptop
-> Gradle builds the Java project
-> deploy task copies code to roboRIO
-> roboRIO restarts or starts the robot program
-> Driver Station reports robot code status
In a WPILib Java project, the important startup files are usually:
Main.javaRobot.javaRobotContainer.java
Main.java starts the WPILib robot program. Robot.java owns the main lifecycle hooks. RobotContainer.java usually constructs subsystems, configures commands, and binds controls.
WPILib calls different methods depending on robot state:
robotInit
robotPeriodic
disabledInit / disabledPeriodic
autonomousInit / autonomousPeriodic
teleopInit / teleopPeriodic
testInit / testPeriodic
In command-based code, robotPeriodic normally runs the command scheduler. That scheduler runs commands, calls subsystem periodic methods, and handles default commands.
This is why periodic code matters. Many robot behaviors are not a one-time function call. They are continuously updated.
Not every device is on CAN. The roboRIO also has direct IO ports.
Common direct connections include:
- DIO for simple digital sensors,
- analog inputs for analog sensors,
- PWM outputs for some motor controllers or LEDs,
- relay outputs,
- I2C and SPI for certain sensors,
- USB for cameras or devices in some setups.
Direct IO can be useful, but it also means the code must match the physical port. A sensor connected to DIO 2 will not work if code reads DIO 3.
Common roboRIO-side issues include:
- robot code is not running,
- code deploy failed,
- the roboRIO is powered but not reachable,
- Driver Station has communication but no robot code,
- a port number does not match wiring,
- CPU or memory usage is too high,
- a loop is blocking and starving periodic code,
- logs show stale or missing sensor values.
Before assuming a subsystem bug, confirm the robot program is actually running.
The Driver Station and roboRIO communicate through the robot network.
In the lab or on the field, the path is usually:
Driver Station laptop
-> robot radio or Ethernet link
-> roboRIO
At competition, the field network and FMS are also involved.
Networking matters because a software symptom may actually be a connection issue. Examples:
- Driver Station has no robot communication.
- Driver Station has communication but robot code is not running.
- NetworkTables dashboards are disconnected.
- The robot radio is not powered correctly.
- The laptop is on the wrong network.
- Ethernet is connected to the wrong device.
Use the Driver Station status indicators before debugging Java. If the robot is not communicating, subsystem code is not the first problem.
A robot is a power system, communication system, and mechanical system controlled by software.
The major hardware categories are:
- power hardware,
- main controller,
- motor controllers,
- motors,
- sensors,
- pneumatics or other actuators,
- networking hardware,
- cameras and coprocessors when used.
Software members do not need to wire the whole robot alone, but you need to understand what your code is talking to.
The battery powers the robot. The simplified path is:
battery
-> main breaker
-> power distribution hardware
-> roboRIO, radio, motor controllers, compressor, sensors, other loads
The power distribution hardware provides protected outputs to different robot devices. Motor controllers draw large currents. The roboRIO, radio, and sensors draw smaller currents but are still affected by bad power.
Power issues can look like software bugs:
- robot reboots,
- radio drops connection,
- motor controllers reset,
- sensors disappear,
- voltage dips during acceleration,
- mechanisms work at low load but fail under high load.
Useful software signals include:
- battery voltage,
- motor supply current,
- motor stator current,
- brownout indicators,
- device faults,
- connection status.
If a robot behaves differently with a fresh battery, power is part of the problem.
CAN is the main robot device network. The roboRIO sends and receives messages on CAN, and devices identify themselves by CAN ID.
Devices commonly on CAN include:
- TalonFX motor controllers,
- CANcoders,
- Pigeon IMU,
- power distribution hardware,
- pneumatics control hardware,
- CAN-based sensors.
The important software ideas:
- each device on the same CAN bus must have a unique ID,
- code must use the correct ID,
- code must use the correct bus name,
- the device must be powered,
- the CAN wiring must be intact,
- termination matters,
- intermittent CAN problems can produce inconsistent behavior.
In code, CAN information usually appears in:
- generated drivetrain constants,
- mechanism config classes,
- subsystem constructors,
- constants files.
For example, a motor controller may be constructed with an ID and bus name:
new TalonFX(14, "rio");If the physical device is ID 15 or on a different bus, the code will not talk to the device you expect.
The roboRIO does not directly power high-current motors. It commands motor controllers.
A motor controller receives a command from code and applies electrical output to a motor. It can also report state back to code.
Common things a motor controller can do:
- apply voltage,
- apply percent output,
- run velocity control,
- run position control,
- enforce current limits,
- brake or coast when neutral,
- report position and velocity,
- report voltage, current, temperature, and faults.
For a TalonFX, the motor controller includes an integrated sensor and supports Phoenix 6 control requests.
The practical debugging model is:
subsystem chooses a target
-> wrapper or IO layer sends a motor request
-> motor controller applies output
-> motor moves the mechanism
-> sensor data comes back
-> logs show target, measurement, output, current, and faults
If a mechanism is wrong, inspect target, measurement, output, and connection status before changing PID constants.
Sensors are how the robot knows what is happening.
Common sensor categories:
- encoders for mechanism position and velocity,
- absolute encoders for known physical angle,
- gyros or IMUs for robot orientation,
- beam breaks or proximity sensors for object detection,
- cameras for vision,
- current and voltage telemetry from motor controllers,
- pressure sensors for pneumatics when used.
Closed-loop control depends on sensor correctness. A good controller with bad sensor data will behave badly.
Sensor debugging questions:
- Is the sensor connected?
- Is the sensor ID or port correct?
- Does the value change when the mechanism moves?
- Does it change in the expected direction?
- Are the units correct?
- Does it reset or wrap unexpectedly?
- Is it absolute or relative?
- Is the code using the right sensor for the control loop?
For example, a wrist position loop needs a position measurement. If the position is inverted, scaled wrong, or stuck at zero, tuning the PID gain will not solve the real problem.
Some robots use pneumatics for simple extend/retract actions. Others use servos, LEDs, or specialty actuators.
The software idea is the same:
code chooses a state
-> hardware interface receives command
-> actuator changes physical state
-> optional sensor confirms result
Pneumatics are often state-based rather than continuously controlled. A solenoid may be commanded extended or retracted. If feedback is available, code can check whether the mechanism reached the expected state.
Common failure modes:
- wrong channel or module ID,
- no pressure,
- electrical connection issue,
- mechanical binding,
- code sets the wrong state,
- no sensor confirms the state.
Some robot functions use cameras or coprocessors for vision processing.
A camera pipeline may:
- detect AprilTags,
- estimate robot pose,
- detect game pieces,
- publish target information over NetworkTables or another interface.
The robot code then consumes that information.
Vision data is different from a simple sensor because it often has:
- latency,
- uncertainty,
- intermittent targets,
- coordinate-frame conversions,
- filtering logic.
When debugging vision, check:
- camera connection,
- timestamp,
- target count,
- pose estimate,
- coordinate frame,
- latency compensation,
- whether the drivetrain actually consumes the measurement.
Most WPILib Java robot projects use a structure like:
src/main/java/frc/robot
Main.java
Robot.java
RobotContainer.java
Constants.java
subsystems/
commands/
lib/
generated/
In our codebase:
-
Robot.javahandles lifecycle, logging setup, and mode-level behavior. -
RobotContainer.javaconstructs subsystems and binds controls. -
subsystems/contains robot systems such as drivetrain, superstructure, and vision. -
lib/contains reusable helper code and abstractions. -
generated/contains generated constants or vendor-generated code. -
vendordeps/declares external libraries. -
src/main/deploy/contains files copied to the robot with the program.
When reading a new area, use this order:
- Find the entry point or wiring.
- Find the subsystem.
- Find the hardware abstraction or vendor wrapper.
- Find constants and configuration.
- Find logs and dashboard outputs.
- Only then edit.
WPILib command-based code separates robot behavior into subsystems and commands.
A subsystem owns hardware or a robot function:
drivetrain
shooter
intake
vision
superstructure
A command tells one or more subsystems what to do:
drive with joystick
run intake
shoot note
follow path
reset pose
A default command is the command a subsystem runs when nothing else is using it. For example, drivetrain joystick driving is usually a default command.
This matters because a method can be correct but never run if the command is not scheduled. When behavior is missing, inspect command scheduling and default commands before editing subsystem internals.
Simulation runs robot code on your laptop instead of on the real robot.
Simulation is useful for:
- checking that code compiles and starts,
- testing command scheduling,
- testing controller bindings,
- observing dashboards,
- checking logs,
- validating simple subsystem logic,
- testing some modeled drivetrain or mechanism behavior.
Simulation is not a complete replacement for the robot.
It cannot fully prove:
- CAN wiring,
- real motor inversion,
- real sensor mounting,
- real battery sag,
- mechanical friction,
- exact driver feel,
- full field network behavior.
Use simulation early, then use real robot testing carefully when needed.
Logs and dashboards are how software gets evidence.
Good signals include:
- selected mode,
- selected goal,
- target position or velocity,
- measured position or velocity,
- applied voltage,
- current draw,
- sensor connection status,
- robot pose,
- module target states,
- module measured states,
- controller inputs.
Without logs, debugging becomes memory and guesswork. With logs, you can compare what the code wanted against what the robot measured.
For mechanism debugging, look for:
goal
measurement
output
mode
current
connection
For drivetrain debugging, look for:
requested chassis speeds
target module states
measured module states
gyro yaw
pose
current draw
A normal workflow is:
- Read the task.
- Find the relevant code path.
- Make a small change.
- Run formatting, compile, or tests when available.
- Run simulation when useful.
- Review the expected physical behavior before deploy.
- Deploy to the roboRIO.
- Use Driver Station to enable in the correct mode.
- Observe logs and physical behavior.
- Iterate based on evidence.
Do not use real robot deploy as the first time you think through what your code does.
Use this pattern for almost every robot issue:
input
-> code path
-> requested state
-> hardware command
-> measured state
-> physical behavior
Then ask where the first mismatch appears.
Examples:
- Controller button is not seen: input problem.
- Button is seen but command does not run: scheduling or binding problem.
- Command runs but target is wrong: logic or setpoint problem.
- Target is right but motor command is wrong: subsystem or wrapper problem.
- Motor command is right but sensor is wrong: sensor, unit, or config problem.
- Sensor is right but mechanism does not move: hardware, power, current limit, mechanical, or motor-controller problem.
This is how you avoid random edits.
Robot code can move heavy mechanisms quickly.
Before enabling:
- know what code changed,
- know what command should run,
- know what hardware could move,
- clear the robot area,
- have someone ready to disable,
- start with a low-risk test,
- watch logs and physical behavior.
If behavior surprises you, disable. Do not debug while the robot is doing something unsafe.
You should be able to explain:
- what the Driver Station does,
- what the roboRIO does,
- how controller input reaches code,
- why enabled and disabled state matters,
- what CAN is used for,
- why motor controllers are separate devices,
- why sensors are required for closed-loop control,
- how power problems can look like software problems,
- what simulation can and cannot prove,
- why logs are central to debugging,
- how code gets from your laptop to the robot,
- how to trace a robot behavior through input, code, command, hardware, measurement, and logs.
The rest of the training lessons use this map. Each lesson goes deeper into one part of the system.