- The big idea
- Compiling Java in a browser
- Running an OpMode
- Shims: how motors and sensors are faked
- Physics and graphics
- Dependencies and environments
- Deploying to the real robot
- Offline mode
- What isn't simulated
- License and warranty
The big idea
FTC robot code is Java that talks to the robot through the FTC SDK: classes like DcMotor, Servo, IMU, Gamepad, Telemetry and LinearOpMode. The simulator provides its own versions of those classes with exactly the same names and methods. In the sim, motor.setPower(0.5) drives a simulated motor. On the robot, the same line drives a real one.
So the code you write in the sim is normal FTC code. When you deploy, the simulator sends your source files, not anything sim-specific, to the robot, and the robot compiles them against the real SDK.
Compiling Java in a browser
Browsers don't run Java, so the simulator brings its own. CheerpJ (from Leaning Technologies) is a full Java 17 virtual machine compiled to WebAssembly. Inside it runs ECJ, the Eclipse Compiler for Java, the same kind of compiler an IDE uses. When you press INIT, the sim hands your .java files to ECJ like this:
ecj -source 1.8 -target 1.8
-bootclasspath jdk-base.jar # the standard Java library
-classpath shim.jar:pedro-core.jar # FTC SDK shims + Pedro Pathing
-proc:none -d /files/<slot>/ YourOpMode.java …
Java 8 language level matches what OnBotJava accepts on a Control Hub, so anything that compiles in the sim will also compile on the robot. Compiler errors come straight from ECJ with real line numbers.
The first compile after loading the page takes about a minute, because the compiler and the Java library load and warm up piece by piece. Later compiles in the same session are much faster.
Running an OpMode
A small Java class called OpModeHost plays the role of the Robot Controller app:
- INIT: it loads your freshly compiled classes with a brand-new class loader, so every INIT runs the code you just saved. It builds the
hardwareMapand starts yourrunOpMode()on its own thread, where it waits atwaitForStart(). - START: it releases
waitForStart()and your loop begins. - Every ~16 ms (about 60 times a second), a second "sampler" thread copies the gamepad into
gamepad1, steps the motor models, and sends the results to the JavaScript side: chassis velocity, intake, feeder, shooter, hood and telemetry. It also reads back the robot's pose and the flywheel encoder. - STOP: it requests a stop, exactly like pressing STOP on a Driver Hub.
Java and JavaScript talk through CheerpJ natives, small functions declared in Java and implemented in JavaScript (for example gpLeftX, simYaw, publish and mech). There are two hosts, red and blue, which is how the two-robot 2UP mode runs two OpModes side by side.
Shims: how motors and sensors are faked
A shim is a stand-in that looks exactly like the real thing from the outside. The simulator keeps two layers:
- The shim layer (
shim.jar): the FTC classes your code compiles against. These are mostly interfaces and annotations, such asDcMotorEx,Servoand@TeleOp. These are what you see. - The sim layer (
app.jar): hidden classes that implement those interfaces and connect them to the physics. These are what actually happens.
| Your code uses | Behind it in the sim |
|---|---|
DcMotor / DcMotorEx (drive) | SimMotor → a goBILDA motor model (312 RPM, 0.15 s spin-up lag) → mecanum kinematics → chassis velocity → physics |
DcMotorEx (shooter) | The sim models flywheel speed from your power, then feeds encoder ticks (28 per rev) back so getVelocity() reads real ticks/second. That closes the loop for the PID lessons. |
Servo | SimServo → position 0–1 → the hood's launch angle |
CRServo | SimCRServo → power −1…1 → the feeder |
IMU | IMUImpl → the robot body's heading from the physics engine |
GoBildaPinpointDriver | Reads the true position from physics, minus the offset you set with setPosition(), so it only knows motion since you set it, like the real device |
Telemetry | SimTelemetry → the simulated Driver Hub screen |
FtcDashboard | Stubs, so code that uses Dashboard still compiles |
One setPower, start to finish
Drive motor
- setPower(0.5)
- SimMotor
- Motor model
- Mecanum math
- Chassis velocity
- Rapier
Each drive motor's model eases toward power × top speed with a short lag, the way a real motor takes a moment to spin up. The four wheel speeds go through standard mecanum kinematics to get a forward, sideways and turning velocity, and the physics engine moves the robot body to match. The left motors are mirrored, just like on a real robot, so the usual "reverse the left motors" code drives correctly.
Hardware names
The simulated hardwareMap answers to the names our robot uses (front_left_motor, intake_motor, shooter, hood, feeder, pinpoint, imu and so on), plus the shorter leftFront-style names used in the lessons. See Robot Configuration for the full list your real Driver Hub needs.
Physics and graphics
- Rapier (a physics engine compiled to WebAssembly) simulates the robot as a rigid body: collisions with walls, the hive and the other robot, game pieces with real mass, and flywheel shots that fly a real arc.
- A controller pushes the robot body toward the chassis velocity your code commands. When nothing is commanded the robot holds still, so it doesn't drift off walls.
- three.js draws the BIOBUZZ field and robots. The field is built from the official field CAD. A graphics setting (High / Auto / Low) keeps slower laptops smooth.
Dependencies and environments
The simulator ships everything it needs from its own website, with nothing loaded from other servers at runtime.
| Component | Role | License |
|---|---|---|
| CheerpJ (Java 17 runtime) | Java virtual machine in WebAssembly | Leaning Technologies' terms |
ECJ (ecj.jar, ~3.3 MB) | Compiles your Java | EPL 2.0 |
jdk-base.jar (~13 MB) | The standard Java library, for compiling | GPL 2 + Classpath Exception (OpenJDK) |
shim.jar / app.jar | FTC SDK shims / simulator runtime | Apache 2.0 (ours) |
Pedro Pathing 2.0.6 (pedro-core.jar, ~108 KB) | Path following for autonomous | BSD 3-Clause |
| three.js r160 | 3D graphics | MIT |
| Rapier 0.14 | Physics | Apache 2.0 |
| CodeMirror | Code editor | MIT |
Pedro Pathing is a real jar
The simulator doesn't imitate Pedro Pathing. It uses the actual Pedro Pathing 2.0.6 library, the same jar a robot uses. It's pure Java and depends only on the standard Java library, so it runs unchanged inside CheerpJ. The sim adds a Pinpoint Localizer and a mecanum Drivetrain so Pedro can read the robot's position and drive the wheels. The Capture panel lets you drive the robot, record poses, and generate a Pedro autonomous OpMode from them.
Environments
Libraries come in versioned bundles called environments. FTC 2026–2027 Standard (SDK 12.0) is the base shims. PedroPathing 2.0.6 adds the Pedro jar plus starter files (PinpointLocalizer, MecanumDrivetrainSubsystem, Robot, Subsystem, Intake). Your code packages are saved in the browser's own storage and can be exported and imported as .zip files.
Deploying to the real robot
Every REV Control Hub runs OnBotJava, a small web server built into the Robot Controller app that stores Java source and compiles it on the robot. The simulator deploys by talking to OnBotJava directly:
- Libraries first, only if needed. If your code imports
com.pedropathingand the robot doesn't have the jar yet, the sim uploads it once. - Save each file into a separate
.obpackage (below), and clean up files left from earlier deploys that you've since deleted. - Build. The Control Hub compiles everything against the real FTC SDK 12.0, and the build log appears in the sim.
Why your OpMode shows up as "… OB"
A robot can already have OpModes built into its app from Android Studio. If OnBotJava compiles a class with the same name, the built-in one wins and your new code silently never runs. To avoid that, the sim deploys into its own package, org.firstinspires.ftc.teamcode.ob, and adds " OB" to each OpMode's name. On the Driver Hub you'll see MecanumDrive OB next to any built-in MecanumDrive, and you can tell exactly which one is your fresh deploy. When you import code back from the robot, the .ob and " OB" are removed again.
Two ways to connect
Plug the Control Hub into the laptop. The browser talks to it directly through WebUSB, using the Android debug protocol (ADB), which the sim implements itself. You don't need Android Studio or adb.exe, though Windows may need the standard Android USB driver once. Needs Chrome or Edge.
Browsers can't open a raw network connection to the robot, so a small helper does it: the Impulse Wi-Fi Bridge, a system-tray app downloaded from the sim's Settings. It listens only on your own computer (127.0.0.1), connects to the Control Hub over ADB on its Wi-Fi network, reconnects on its own when Wi-Fi drops, and warns you if the hub's debug service gets stuck so you can power-cycle it.
When you deploy, the sim checks both and picks for you: the cable wins if it's plugged in, otherwise it uses Wi-Fi. You can override the choice. Both routes run exactly the same deploy steps.
It's a single portable .exe for Windows, with no installer and nothing added to startup. It isn't code-signed yet, so Windows SmartScreen will warn you the first time ("More info → Run anyway"). To remove it, quit it from the tray, delete the .exe, and delete the %AppData%\impulse-wifi-bridge folder (it only remembers your robot's Wi-Fi name).
Offline mode
Competition venues often have no usable internet, and a robot laptop is usually connected to the robot's Wi-Fi instead. So the simulator works fully offline:
- It's an installable web app. In Chrome or Edge, use Install app, or the download button in the sim.
- A service worker keeps two caches: the app itself (refreshed with each new version) and the big runtime pieces (the Java runtime and jars), which are saved the first time they're used.
- The Wi-Fi Bridge download is cached too, so a robot laptop can install it without internet.
- The top bar shows Online or Offline, and Settings has Reset offline data if anything ever gets stuck.
While you're online, open the sim on the competition laptop and run one full INIT. That's what pulls the compiler and Java runtime into the cache. After that, it works with no network at all.
What isn't simulated
A simulator is a model, and it's honest about where it simplifies:
- No battery sag. Motors don't slow down as the battery drains, unlike the real robot (see Electrical Systems).
- Perfect odometry. The simulated Pinpoint has no drift or noise.
- No cameras or vision. AprilTag and color processing aren't simulated.
- Our robot's hardware only. The
hardwareMapknows our device names, not every possible sensor. - Browser limits. USB deploy needs Chrome or Edge on a computer, and the Wi-Fi bridge is Windows-only for now.
That's why the real robot is always the final test. The sim gets your logic right fast, and the robot tells you about the physical world.
License and warranty
The Impulse 3D Simulator is free to use. It's open source under the Apache License 2.0 (© 2026 Bolton Robotics FTC), and the Wi-Fi Bridge is under the MIT License. You're welcome to use it with your own team. If you reuse or modify it, keep the attribution described in the project's NOTICE file and on our Use & Attribution page.
As both licenses say, the software is provided "as is", without warranty of any kind, express or implied. We built it to help students learn, and we test it on our own robots, but use it at your own risk, especially when deploying to competition hardware.
Third-party components (CheerpJ, ECJ, three.js, Rapier, CodeMirror, Pedro Pathing) remain under their own licenses. The FTC class names in the shims are independent re-implementations, written for compatibility and education. FIRST® and FIRST® Tech Challenge are trademarks of FIRST, which does not sponsor, authorize or endorse this project.