-
Notifications
You must be signed in to change notification settings - Fork 1
Lesson 2: Codebase and Simulation
Finish reading Lesson 1 and complete Lesson 1 Task.
- Understand the top-level flow of a WPILib Java robot project.
- Navigate the main folders in our 2026 repos.
- Run simulation and understand what the
sim/config is doing. - Use AdvantageScope to inspect logs and visualization output.
1-2 hours
- Main robot lifecycle: 971-second-robot-2026/src/main/java/frc/robot/Robot.java
- Wiring and subsystem setup: 971-second-robot-2026/src/main/java/frc/robot/RobotContainer.java
- Controller bindings: 971-second-robot-2026/src/main/java/frc/robot/subsystems/Controllers.java
- Simulation config notes: 971-second-robot-2026/sim/README.md
- Example visualization reference: 971-second-robot-2026/src/main/java/frc/robot/subsystems/superstructure/Visualization.java
Before diving into our specific code, understand the WPILib lifecycle that every robot project follows. This is the skeleton our code fills in the details.
Every WPILib robot program starts in a single main() method.
public static void main(String... args) {
RobotBase.startRobot(Robot::new);
}This tells WPILib to construct our Robot class and manage its lifecycle. You should never need to edit this file.
WPILib calls methods on your Robot class in a fixed order during a match:
| Phase | Method | When | Runs |
|---|---|---|---|
| Power on | robotInit() |
Once when robot boots | Once |
| Disabled | disabledInit() |
When disabled (before auto, between auto/teleop, after match) | Each disable |
| Disabled loop | disabledPeriodic() |
While disabled, ~20 ms loop | Repeated |
| Auto start | autonomousInit() |
When auto begins | Once per auto |
| Auto loop | autonomousPeriodic() |
During auto, ~20 ms loop | Repeated |
| Auto end | autonomousExit() |
When auto ends | Once per auto |
| Teleop start | teleopInit() |
When teleop begins | Once per teleop |
| Teleop loop | teleopPeriodic() |
During teleop, ~20 ms loop | Repeated |
| Teleop end | teleopExit() |
When teleop ends | Once per teleop |
| Every loop | robotPeriodic() |
Every 20 ms regardless of mode | Every cycle |
The robotPeriodic() method runs every 20 ms for the entire lifetime of the robot and is where you put logic that must run in every mode (vision updates, logging, command scheduler ticks).
WPILib provides a command-based framework on top of this lifecycle. The key concepts:
- Subsystem — a piece of robot hardware (drivetrain, shooter, intake). Each subsystem owns its actuators and sensors.
- Command — a discrete action that runs for a bounded time ("shoot for 2 seconds", "run intake until sensor triggers"). Commands require subsystems, ensuring a subsystem isn't controlled by two commands at once.
-
CommandScheduler — the central dispatcher. Each
robotPeriodic()tick, it runs all active commands and checks which idle commands should start based on their triggers. - Default Command — a command automatically running on a subsystem whenever no other command is. For the drivetrain, this is always driver control.
In our code, CommandScheduler.getInstance().run() at the bottom of robotPeriodic() is what makes everything move. Without that one line, no commands ever execute.
Driver sticks a joystick
-> Controllers.java reads the input as a Trigger or axis value
-> RobotContainer.java default command reads the controller values
-> Drivetrain receives a SwerveRequest (speeds, direction)
-> Phoenix motors execute over CAN
-> Encoders report back new positions
-> Odometry updates the robot's estimated pose
-> Logger records the pose to NetworkTables / log file
-> AdvantageScope / SimGui displays the robot on a field
Understanding this chain end-to-end is more important than memorizing any single file. When something goes wrong, trace the chain from input to output.
Use this lesson to explain the project structure from the outside in. Open the 971-second-robot-2026 folder in VS Code and explore each path:
971-second-robot-2026/
├── build.gradle # Gradle build config, dependencies, sim support
├── vendordeps/ # Third-party JSON library descriptors
├── sim/ # SimGui window layout + key mapping JSON
├── ascope_assets/ # AdvantageScope 3D robot model (.glb files)
├── scripts/ # Utility scripts (flip-auto.py, extract-logs.sh, etc.)
├── src/main/deploy/ # Files copied to robot at deploy time
└── src/main/java/frc/robot/ # All robot code
frc/robot/
├── Main.java # Entry point — never edit
├── Robot.java # Lifecycle: init, periodic, mode transitions
├── RobotContainer.java # Wires subsystems + controllers + default commands
├── Constants.java # Mode (REAL/SIM/REPLAY), sim physics, PID tuning
├── Telemetry.java # Publishes drivetrain state to NetworkTables + logs
├── generated/
│ └── TunerConstants.java # CTRE Phoenix Tuner output — DO NOT HAND-EDIT
├── lib/
│ ├── JoystickValues.java # Joystick input processing (deadband, curve, slew)
│ ├── shooter/ # Shooter physics solver, speed tables, shot math
│ ├── simulation/ # MapleSim swerve physics integration
│ └── superstructure/ # Motor/sensor abstractions (MotorIO, CANRange, Toggle, Edge)
└── subsystems/
├── CommandSwerveDrivetrain.java # Swerve drivetrain + MapleSim + SysId + logging
├── Controllers.java # Xbox controller bindings (TROY=driver, ANDRE=operator)
├── Autos.java # BLine auto routines + SmartDashboard chooser
├── HubShiftUtil.java # Hub shift game-state tracking
├── superstructure/ # All mechanism subsystems (turrets, hoods, flywheels, intake)
└── vision/ # BOS (vision odometry) + TagHelper
-
src/main/java/frc/robot— lifecycle classes (Robot,Main) and the wiring layer (RobotContainer). These are the first files you read to understand any WPILib robot project. -
subsystems/— the bulk of robot logic. Drivetrain, autos, controllers, vision, and all superstructure mechanisms. Each subsystem is a self-contained unit that controls specific hardware. -
lib/— reusable helpers and lower-level abstractions. These classes are used by subsystems but don't own hardware themselves. Examples:JoystickValues(input curve/slew),Edge/Toggle(one-shot button detection),MotorIO(motor interface), shooter physics math. -
generated/— auto-generated constants from the CTRE Phoenix Tuner tool. Never hand-editTunerConstants.java; re-run the Tuner if hardware changes. -
src/main/deploy— files copied to the RoboRIO at deploy time. This is where autonomous path JSON files live:-
autos/paths/— BLine path definitions (F_Normal.json, S_Normal.json, H_Normal.json, etc.) -
autos/config.json— BLine global configuration -
pathplanner/— PathPlanner paths and autos (backup/alternative auto system)
-
-
vendordeps/— JSON files that tell Gradle where to download third-party libraries. Each JSON file is a "vendor dependency" that adds classes to your project:-
Phoenix6-frc2026-latest.json— CTRE Phoenix 6 (motor controllers, Pigeon 2 gyro, CANdevices) -
AdvantageKit.json— AdvantageKit (logging, replay, visualization) -
BLine-Lib.json— BLine (vision-based autonomous path following) -
PathplannerLib.json— PathPlanner (alternative path generation tool) -
maple-sim.json— MapleSim (swerve drivetrain physics simulation) -
WPILibNewCommands.json— WPILib command-based framework
-
-
sim/— local simulation GUI configuration. Contains three JSON files and an HTML key mapping reference. More below. -
ascope_assets/— 3D robot model files (.glb) and aconfig.jsonthat maps AdvantageKit visualization components to physical joints on the robot. This is what lets AdvantageScope show a 3D robot that moves as you drive in sim.
New members often make the mistake of reading every file as if all files are equally important. They are not.
For a first pass:
-
Start with the lifecycle entry point. Open
Robot.javaand read the constructor androbotPeriodic(). This tells you what subsystems exist and what runs every cycle. -
Find the wiring and input layer. Open
RobotContainer.java. This shows you how subsystems are connected and what the default command (always-running driver control) does. -
Identify the major subsystems. Look at the
subsystems/folder. Read the top-level class in each subfolder to understand what hardware it controls. Don't read every method — scan field declarations and constructor parameters. -
Look at deploy assets and library markers. Glance at
src/main/deploy/to see what path files exist. Checkvendordeps/to understand what third-party libraries the robot depends on. - Only then dive into one subsystem deeply. Pick one mechanism — the drivetrain, a shooter, an intake — and read its full implementation.
Open Robot.java and trace what happens:
The constructor (Robot()):
- Records metadata to the logger (project name, team number, robot name).
- Branches on
Constants.MODE:-
REAL — logs to a
.wpilogfile on the RoboRIO AND publishes to NetworkTables (NT4Publisher). This is match day. - SIM — publishes only to NetworkTables. This is desktop simulation.
-
REPLAY — reads an old
.wpilogfile and replays it. This is post-match analysis. A secondary writer saves a_simsuffix log with simulated data overlaid on the replay.
-
REAL — logs to a
- Calls
Logger.start()— AdvantageKit begins recording. - Initializes
TagHelper(vision tag lookup),RobotContainer(wires everything),BOS(camera-based odometry), andAutos(auto routines). - Key insight: By the time the constructor finishes, the entire robot is constructed and wired. No subsystem is created lazily.
robotInit():
- Starts
DataLogManager(WPILib's built-in logging). - Calls
robotContainer.resetSuperstructure()to zero all mechanism encoders.
robotPeriodic() — the heart of the robot:
Every 20 ms, this method:
- Calls
robotContainer.periodic()→ which callssuperstructure.periodic()→ which runs all teleop/auto mechanism logic and callsperiodic()on every individual motor subsystem. - Logs hub shift timing info (game-state tracking for our 2026 game strategy).
- Calls
bos.updatePose()— updates the vision-based pose estimate. - Checks
Controllers.ODOMETRY_RESET(driver Y button) — if pressed, resets the drivetrain pose to the last vision reading. - Checks
Controllers.DISABLE_OTF(operator X button) — same pose reset, used when On-The-Fly aiming is disabled. - Calls
CommandScheduler.getInstance().run()— executes all active commands and evaluates triggers. This is the line that makes the robot do anything.
disabledPeriodic():
- Computes the autonomous start pose from the currently selected auto routine.
- Flips the pose to the red alliance coordinate system if on red.
- Sends the pose to telemetry so it shows on the SimGui field.
autonomousInit():
- Gets the auto command from the
Autoschooser. - Schedules
superstructure.neutral()(resets all mechanisms to stowed positions). - Schedules the autonomous command.
- Re-initializes hub shift tracking.
teleopInit():
- Cancels the autonomous command if still running (e.g., auto ran longer than 15 seconds).
- Re-initializes hub shift tracking.
- The drivetrain's default command (driver control) automatically starts because no command is explicitly scheduled — the CommandScheduler handles this.
Open RobotContainer.java and trace the wiring:
Field declarations:
- Creates a
Superstructure(which in turn creates all mechanism subsystems). - Defines three
SwerveRequest.FieldCentricconfigurations with different speed profiles:-
drive— full speed (3.5 m/s translation, 0.8 rot/s angular) -
shootingDrive— 30% speed for steady aiming while shooting -
shuttlingDrive— 50% speed for careful left/right shuttle movement
-
- Each profile has its own deadband and slew rate limiters to prevent jarring transitions.
- Creates the drivetrain via
TunerConstants.createDrivetrain().
The constructor:
- Creates the
Superstructure(passingthisso superstructure can reference the drivetrain). - Calls
configureDrivetrain()— sets the default command. - Silences the joystick connection warning (cosmetic).
- Registers the telemetry callback:
drivetrain.registerTelemetry(logger::telemeterize). - In simulation only, resets the robot pose to field center
(3, 3, 0). - Registers BLine event triggers — these fire commands at specific points along an auto path:
-
"shoot"→superstructure.shootAuto() -
"shootNoJuice"→superstructure.shootAutoNoJuice() -
"neutral"→superstructure.neutral() -
"intakeDown"→superstructure.intakePivotDownAuto()
-
configureDrivetrain() — the default command:
This is the most important method for understanding driver control. The drivetrain's default command:
- Reads the driver controller (
Controllers.TROY) left stick for translation and right stick for rotation. - If the operator holds the shoot trigger and the driver isn't trying to move, applies a brake (stops the robot for a stable shot).
- Otherwise, cross-fades between the normal/shooting/shuttling speed profiles based on operator controller state (
Controllers.SHOOTING,Controllers.SHUTTLING). - Applies joystick input through
JoystickValues— exponential curve shaping and slew rate limiting for smooth control.
Open Controllers.java. This file defines two Xbox controllers:
- TROY (port 0) — the driver. Controls drivetrain via left stick, has intake pivot toggle (left bumper), intake rollers (left trigger), shoot redundancy (right trigger), odometry reset (Y).
- ANDRE (port 1) — the operator. Controls shooting (right trigger), shuttling (bumpers), manual mode toggle (Y), OTF disable (X), and D-pad fine-tuning for flywheel and turret setpoints.
Notice the abstractions:
-
Toggle— tracks button state changes (on/off/on/off). Used for intake pivot and manual mode. -
Edge— fires once on the rising edge of a button press. Used for D-pad setpoint adjustments so holding the button doesn't increment repeatedly. - Composite triggers like
SHOOTING = SHOOT_REDUNDANCY.or(SHOOT)allow either the driver or operator to initiate a shot.
Open subsystems/superstructure/Visualization.java. This class:
- Defines static
Transform3dconstants that describe the kinematic chain — the physical offset from robot center to each joint (turrets, hoods, ground pivot). - In
periodic(), composes live encoder readings into full 3D poses for each component. - Logs all five component poses via
Logger.recordOutput("Visualization/Components", ...). - The
ascope_assets/Robot_First/config.jsonfile maps these logged transforms to animated joints on the 3D robot model.
When you open AdvantageScope during simulation, you can see the robot model's turrets rotate and hoods tilt in real time as the code runs.
##Watch this video: FRC 971 - WPILib Simulator and AdvantageScope Tutorial.
WPILib simulation is useful because it gives you a place to verify control flow before real robot time is available.
Use this lesson to make that distinction explicit:
- What simulation does well: tests control flow (does pressing the shoot trigger actually call the shooter commands?), verifies wiring (are controllers mapped to the right ports?), catches null pointer exceptions before deploy, and models physics approximately (MapleSim simulates swerve wheel friction, robot mass, and inertia).
- What simulation cannot prove: exact motor current draw, real CAN bus timing, encoder noise, wire lengths, mechanical binding, battery sag under load, camera latency, or RF interference.
- Why it is still worth using: it catches obvious wiring and control-flow mistakes early. A command that never schedules in sim will never schedule on the robot either.
-
build.gradleenables desktop simulation:def includeDesktopSupport = true wpi.sim.addGui().defaultEnabled = true wpi.sim.addDriverstation()
This tells GradleRIO to compile and run the robot program as a desktop Java application instead of deploying to a RoboRIO. The
addGui()call launches SimGui (the WPILib simulation dashboard), andaddDriverstation()emulates a Driver Station for testing auto/teleop mode transitions. -
Running simulation in VS Code:
- Either
Command + Shift + P(Mac) orCtrl + Shift + P(Windows) and select WPILib: Simulate Robot Code from the dropdown or type./gradlew simulateJavain the terminal. - VS Code compiles the project and runs
java -cp ... frc.robot.Mainon your desktop. - SimGui opens automatically, showing the field, dashboard, and robot state.
- The robot program thinks it is running —
robotInit(),robotPeriodic(), and all periodic methods execute on their normal 20 ms loop.
- Either
-
The
sim/folder: Contains saved SimGui window layout and keyboard-to-joystick mapping JSON files:-
simgui.json— NetworkTables window configuration (field view, robot pose visualization, SmartDashboard bindings, data types). Configures the field to show robot pose as a pink arrow with a green body. -
simgui-ds.json— keyboard mappings for two virtual Xbox controllers:- Keyboard 0 (Driver): WASD = left stick, Arrow keys = right stick, U/O = triggers, 1-0 = face buttons
- Keyboard 1 (Operator): Q/E = left X, P/; = right Y, T/G/H/F = POV, Z/X/C/V/B/N/M/=/,/= = face buttons
-
simgui-window.json— dock layout for the SimGui window (19 panels arranged in a grid). -
Simulation Key Mapping.html— a visual reference you can open in a browser showing colored keyboard diagrams.
Before first run, copy the sim config to the project root:
cp sim/simgui*.json .
SimGui reads these files from the project root. The
sim/folder is the "source of truth"; the copies at root are the "deployed" config. -
-
The FMS (Field Management System) in SimGui: The Robot State / FMS panel lets you simulate match events:
- Click "Auto" → "Enable" to enter autonomous mode (triggers
autonomousInit()). - After 15 seconds (or click "Teleop" → "Enable") to enter teleop (triggers
teleopInit()). - Click "Disable" to return to disabled mode.
- Use the alliance color selector to test red-alliance coordinate flipping.
- Click "Auto" → "Enable" to enter autonomous mode (triggers
| Works in sim | Does NOT work the same in sim |
|---|---|
| Command scheduling, default commands | Real CAN bus latency and packet loss |
| Controller inputs via keyboard | Encoder noise, slip, and missed packets |
| MapleSim swerve physics (approximate) | Exact wheel traction, carpet friction |
| NetworkTables publishing/subscribing | Real camera latency and frame drops |
| AdvantageScope 3D visualization | Mechanical binding, gear backlash |
| Auto path playback | Battery voltage sag under high current |
| Mode transitions (disabled → auto → teleop) | Real RoboRIO timing jitter |
Rule of thumb: If it doesn't work in sim, it won't work on the robot. If it works in sim, it probably works on the robot — but still test on hardware before trusting it.
This repo uses AdvantageKit for all logging. AdvantageKit replaces the traditional SmartDashboard/logs combination with a unified system that records every signal to a .wpilog file and publishes to NetworkTables simultaneously.
In Robot.java, the constructor branches on Constants.MODE:
switch (Constants.MODE) {
case REAL -> {
Logger.addDataReceiver(new WPILOGWriter()); // writes .wpilog to RoboRIO
Logger.addDataReceiver(new NT4Publisher()); // publishes to NetworkTables
}
case SIM -> {
Logger.addDataReceiver(new NT4Publisher()); // NetworkTables only
}
case REPLAY -> {
setUseTiming(false); // use log timestamps, not wall clock
String logPath = LogFileUtil.findReplayLog();
Logger.setReplaySource(new WPILOGReader(logPath)); // read old log
Logger.addDataReceiver(new WPILOGWriter(LogFileUtil.addPathSuffix(logPath, "_sim"))); // write sim overlay
}
}
Logger.start();-
REAL mode (match day): every
Logger.recordOutput()call writes to a.wpilogfile on the RoboRIO flash AND publishes to NetworkTables. The log file survives robot restarts and can be downloaded for post-match analysis. -
SIM mode (desktop simulation): publishes to NetworkTables only. No
.wpilogfile is written during normal sim runs (since sim is fast to restart, you usually just re-run instead of replaying). -
REPLAY mode (post-match analysis): reads an existing
.wpilogfile as its source of truth. AllLogger.recordInput()values come from the log, so the simulation is deterministic — you get the exact same sensor readings every replay. The_simsuffix writer records simulated outputs alongside the replayed inputs for comparison.
To run a replay:
./gradlew replayWatchThen place a .wpilog file at src/main/deploy/.advantagekit/replay/log.wpilog, or use the AdvantageScope replay UI to select a log file.
Two methods, different purposes:
-
Logger.recordOutput("key", value)— records a value to the log and publishes to NetworkTables. Use this for values you want to see in AdvantageScope or analyze later. Our code logs poses, motor currents, IMU data, hub shift state, and superstructure visualization. -
Logger.recordInput("key", value)— records sensor inputs. In REPLAY mode, these values are read from the log instead of live sensors, making replays deterministic.
AdvantageScope is the companion desktop application to AdvantageKit. It connects to your robot's NetworkTables (or reads log files) and provides:
-
Field view — shows robot pose, auto start pose, and trajectory on a rendered field. Open via the
/PoseNetworkTables entry. -
3D robot visualization — shows the robot model from
ascope_assets/with animated joints driven byVisualization/Componentslogged transforms. Turrets rotate, hoods tilt, ground pivot angles — all in real time. -
Polars — time-series graphs of any logged signal. Plot motor currents, encoder positions, joystick inputs, or any
Logger.recordOutput()key. - Alerts — displays warnings and errors published via the AdvantageKit alert system.
- System stats — CPU usage, loop timing, memory, CAN status.
To open AdvantageScope:
- Launch it from the WPILib tools directory, or from your applications folder after WPILib install.
- Connect via NetworkTables by entering your robot's IP (real robot) or
127.0.0.1(simulation). - Or open a
.wpilogfile directly for offline analysis.
- It gives you evidence. Instead of "I thought the shooter ran," you can show the exact flywheel RPM over time.
- It helps you debug without guessing. If the robot didn't shoot, check the log: was the shoot command scheduled? Did the shooter reach speed? Was the indexer running?
- It lets you inspect behavior after the run. A match lasts 135 seconds. You can't observe everything live. The log captures everything so you can review afterward.
Many first tasks do not involve writing a whole new subsystem. They involve understanding:
- Where state lives — subsystem fields hold the current state of mechanisms (positions, velocities, setpoints).
-
Where a control decision is made —
Superstructure.periodic()contains the teleop/auto logic tree that decides which setpoint to apply based on controller inputs and game state. -
Where logs should be added — any new debug value goes through
Logger.recordOutput()orLogger.recordInput(). - How to observe whether the code path actually ran — check AdvantageScope polars, check the field view, or add a one-off log line and re-run.
Software members should know the code is not acting on abstract variables. It is commanding hardware over CAN, reading sensors, and trying to move mechanisms with real constraints. Even in sim, keep asking "what hardware would this line affect on a robot?"
When you write flywheelLeft.setVelocity(500 RPM), a Talon FX motor controller receives a CAN message and drives current through a Kraken X60 motor. When you read getPigeon2().getYaw(), you are reading an IMU angle over CANFD. When you call groundPivot.setFeedforward(Volts.of(-0.4)), you are applying a voltage offset to fight gravity on a pivot joint.
Understanding the hardware behind the abstraction makes you a better software engineer on this team. Talk to the mech and elec leads when your code touches a mechanism you haven't seen physically.
-
Open
Robot.javaand explain what happens in:- The constructor — what are the three modes? What does each mode configure for logging?
-
robotPeriodic()— what runs every 20 ms? What is the last line and why is it critical? -
autonomousInit()— how is the auto command obtained and scheduled? What else runs during auto? -
teleopInit()— what happens to the auto command? Why?
-
Open
RobotContainer.javaand trace how the drivetrain default command is chosen:- What three drive profiles exist and when does each activate?
- What happens when the operator holds shoot and the driver doesn't move?
- How does the code decide between shooting and shuttling speed profiles?
-
Open
Controllers.javaand identify:- Which controller port is driver vs operator?
- What does
SHOOTINGcombine? What doesSHUTTLINGrequire? - What is the difference between a
Toggleand anEdge?
-
Copy the sim config files to the project root:
cd 971-second-robot-2026 cp sim/simgui*.json .
-
Run the simulator from VS Code (Run and Debug → "Run Simulation"). Verify:
- SimGui opens with a field view and dashboard.
- You can drive with WASD + arrow keys (driver keyboard mapping).
- The robot pose updates on the field as you drive.
- Pressing the operator shoot key (right trigger mapping) causes the drivetrain to brake.
-
Open AdvantageScope and connect to
127.0.0.1. Identify:- What controls the driver and operator inputs (check
sim/simgui-ds.jsonorSimulation Key Mapping.html). - Where pose or telemetry changes can be seen (the field view, the
DriveStateNetworkTables topic). - What logs or visual outputs are available (check
Drive/Pose,Drive/IMU/,Drive/Currents/,Visualization/Components,HubShift/).
- What controls the driver and operator inputs (check
- Pick one logged signal — for example
Drive/Pose— and trace it through the code:- Where is it recorded? (
CommandSwerveDrivetrain.periodic()callsLogger.recordOutput("Drive/Pose", getState().Pose)) - Where does the value come from? (
getState().Posecomes from the Phoenix swerve odometry, which fuses encoder readings and IMU data) - Where does it go? (AdvantageKit writes it to the log and publishes to NetworkTables; AdvantageScope reads it from NetworkTables and draws the robot on the field)
- Where is it recorded? (
Use these when things go wrong during the exercise:
-
Sim runs but behavior is confusing. Find the default command or trigger path first. The drivetrain default command in
RobotContainer.configureDrivetrain()is almost always where driver control issues originate. -
Controls do nothing. Inspect
Controllers.javabefore changing subsystem logic. The most common mistake is wiring a button to the wrong controller port or confusinggetAsBoolean()withtoggled()/ edge detection. -
A value changes but nothing visible happens. Ask whether it is only logged (check
Logger.recordOutput), only simulated (check if MapleSim consumes it), or actually consumed by a subsystemperiodic()method. -
SimGui doesn't show the field. Check that the
simgui*.jsonfiles are at the project root, not just insim/. SimGui reads from the working directory. -
AdvantageScope can't connect. Verify the sim process is running first, then check that you're connecting to
127.0.0.1on the default NetworkTables port (1735 for NT4). -
The 3D robot model doesn't animate. Check that
Visualization.periodic()is being called (it is, fromSuperstructure.periodic()) and that theascope_assets/Robot_First/config.jsoncomponent positions match theTransform3doffsets inVisualization.java.
- Re-read the superstructure folder names so Week 3 is less overwhelming. Specifically look at
TurretLeft,TurretRight,HoodLeft,HoodRight,FlywheelLeft,FlywheelRight,GroundPivot,GroundRollers,RollerFloor,B2,Kicker, andShooterHandler. - Be ready to talk about control loops, motor abstractions, and CTRE Phoenix structure (Talon FX, Kraken X60, CAN bus, PID + feedforward).
- Try driving the robot in sim and pressing every button on both controllers. Notice what happens and what doesn't — you'll understand why in the next lessons.