Skip to main content
REBUILT 2026 supports full WPILib desktop simulation including ground-truth drivetrain physics, vision simulation, and fuel (game piece) trajectory simulation. All simulation-specific logic is isolated inside a single SimWrapper class so that Robot and the rest of the codebase remain unaware of whether they are running on a real robot or on a desktop.

Running the simulator

1

Start the simulation

Run the Gradle simulation task from the project root:
The WPILib Simulation GUI opens automatically because wpi.sim.addGui().defaultEnabled = true is set in build.gradle.
2

High-fidelity vision (optional)

Add -PhighFidelityVision=true to switch all three cameras from 320 × 240 to 1280 × 800 with tighter calibration noise:
This flag is read as a JVM system property (highFidelityVision) inside VisionSimConstants and affects resolution, calibration error, minimum target area, and distance-variance scale.
JVM heap flags -Xmx2G -Xms2G are applied automatically to every simulate* Gradle task via build.gradle:
You do not need to set these manually.

SimWrapper — unified simulation entry point

SimWrapper is the single object that owns every simulation concern. It is constructed in Robot only when Robot.isSimulation() is true, and the reference is null on a real robot:
Internally SimWrapper holds:

SimWrapper lifecycle

robotPeriodic()

Called from Robot.robotPeriodic() before VisionSubsystem.update(). This ensures that the Limelight NetworkTables entries are populated with fresh synthetic vision data before any code in the same loop reads them:
Inside SimWrapper.robotPeriodic(), every camera’s VisionSimInterface::periodic is called, which runs pose estimation and writes botpose_wpiblue, botpose_orb_wpiblue, and all other Limelight-format entries to the relevant limelight-* NetworkTable.

simulationPeriodic()

Called from Robot.simulationPeriodic(). Runs in order:
  1. Ground-truth physics — m_groundTruthSim.simulationPeriodic() integrates the drivetrain chassis speeds to advance the ground-truth pose and publishes telemetry to SmartDashboard.
  2. Vision scene update — m_sharedVisionSystemSim.update(groundTruthPose) moves all simulated cameras to the ground-truth position so they see the correct AprilTags.
  3. NT publish — m_groundTruthPosePublisher.set(groundTruthPose) sends the ground-truth pose to DriveState/GroundTruthPose.
  4. Field2d visualization — m_showVisionOnField draws both the odometry-estimated pose (with swerve modules) and the ground-truth pose on the shared Field2d.

GroundTruthSim

GroundTruthSim (created by GroundTruthSimFactory) drives the CTRE SwerveDrivetrain simulation loop. Each call to simulationPeriodic() integrates the drivetrain’s reported ChassisSpeeds forward in time to advance a Pose2d that represents the robot’s physical location — independent of any drift introduced into the pose estimator. The ground-truth pose is published to SmartDashboard under Sim/GroundTruth/* and to DriveState/GroundTruthPose via NetworkTables.

RobotSim and FuelSim

RobotSim wraps FuelSim into a single game-piece simulation object. It is constructed alongside SimWrapper in Robot:
RobotSim registers the robot’s geometry (0.8 m × 0.8 m, 0.7 m bumper height) and an intake bounding box with FuelSim, and starts the physics thread. resetFuelSim() is called at the start of autonomous to clear all field fuel and respawn the starting configuration:
FuelSim.launchFuel() models fuel game pieces being launched with full ballistics (gravity, optional air resistance, coefficient-of-restitution collisions with the field, hubs, and trench). The sim launcher command calls:
Scored fuel positions are published to Fuel Simulation/Fuels and the running score is published to Fuel Simulation/Score.

Simulation controller shortcuts

Two POV (D-pad) bindings on the driver controller are active only in simulation:
Use the D-pad on the driver controller to stress-test vision correction without writing any extra code: