A flat index of this site. Every page, what is on it, and when to read it — so an agent can go straight to the right page instead of crawling navigation.
SimLoop is a season-agnostic JVM simulation library for FIRST Tech Challenge robot code. Package root
org.horizon36596.simloop. Version 0.2.0-alpha.2. Licence BSD-3-Clause: use, modify and ship it freely, and license your own robot code however you like; keep the copyright notice with any copy. Status: alpha, so pin an exact version; the API may change between alpha versions. v0.2.0-alpha.2 is the current alpha and v0.1.0-beta1 is superseded. The coordinate is com.github.Horizon-36596:simloop:v0.2.0-alpha.2 from JitPack, and the version keeps its leading v because a JitPack version IS the git tag. The consuming project must be on FTC SDK 12.0.
Check the dependency's exact tag or source commit before using this index. It describes the current
source tree, which can be newer than v0.2.0-alpha.2. Distortion, occluders, tilted tags and synthetic
frames arrived in v0.2.0-alpha.2 and are absent from v0.2.0-alpha.1. Read the matching source or
generated API reference before calling an API newer than your pinned tag.
- Every feature: one line per feature, with a link to its page.
- What it does not do: the authoritative list of what is out of scope. If a task needs something on that list, there is no API for it; say so rather than searching. A photoreal camera image, intake rollers, a shipped field, a command scheduler and controller tuning are out of scope. Game-piece physics, a camera with distortion and occlusion, synthetic frames (flat colours, never for tuning colour thresholds) and fitting to a real log exist, each with stated limits.
| Page | Contains | Read it when |
|---|---|---|
| What SimLoop is | The idea, the package table, the four rules the module holds itself to. | Orienting. |
| Every feature | Every feature, one line each, grouped, each linked to its page. | Checking whether a feature exists. |
| Installing it | The complete Gradle change: both repository lines, the dependency, and the JUnit 5 switch — or the one-folder starter that carries all of it. | Writing or fixing a build file. |
| Your first simulated test | A complete runnable test — fake motor, plant, controller, scenario, scored result. The same file runs in CI. | Writing a first test, or a template for any test. |
| What has been tested | What has been checked so far and what has not; one team, one robot, no comparison with a real robot yet. | Before trusting a sim number as a robot number. |
| What it does not do | Every deliberate boundary, with the reason, plus known rough edges. | Before planning anything; before claiming a feature exists. |
| Packages overview | Which package does what and how they connect. | Choosing where a thing lives. |
fakehardware |
Fake SDK 12.0 devices and FakeHardwareMap: motors with the hub's closed loops, servos, IMU, Pinpoint, OTOS, Limelight 3A, touch, distance and colour sensors. Ticks, volts, [-1, 1] power; millimetres and radians on the odometry seam. |
Wiring hardware into a test. |
plant |
First-order mechanism and drivetrain models: time constant, max speed, end stops, gravity fraction. Drivetrain pose is in the localizer frame: +x forward, +y left, CCW-positive. | Modelling motion, or explaining a response. |
config |
Configuration interfaces and units; strafe-speed and mounting-sign defaults to check against the robot. | Writing a robot's sim config. |
sim |
FakeTimer, ScenarioRunner, RlogDecodedCompare. The four reasons a run refuses to return a log. |
Running a scenario, or diagnosing a thrown run. |
opmode |
OpModeRunner: an unchanged OpMode or LinearOpMode through INIT, the loop and STOP, with scripted gamepads and recorded telemetry. |
Testing an OpMode as written. |
simclock |
How OpModeRunner.forTeamClass moves a team's own ElapsedTime, sleep and System.nanoTime() onto sim time, and what it cannot move. |
Timer code that reads the real clock. |
sim.live |
Keyboard driving, recorded gamepad tracks, headless replay to the identical log, and how to use the unpublished keyboard-window module. | Driving the sim by hand, or replaying a session. |
field |
Game pieces with possession and physics (roll, bounce, fly, score), goals, obstacles, kinematic and hinged bodies, the robot as boxes, robot contact, and FieldFrameTransform. Intaking is a box test. |
Modelling game pieces or the field, or crossing between the two frames. |
sensor |
RangeFinder, ColorProbe, ContactSwitch: what a sensor on a robot mount sees on the field, driving the sensor fakes. |
Simulating touch, distance or colour sensors. |
vision |
SimCamera, SimTagCamera, lens (with distortion), mount, CameraOccluders: which pieces and AprilTags a camera sees, and where. SimFrameRenderer: synthetic RGB frames for running a pixel pipeline, not for tuning it. |
Testing a vision pipeline's geometry, or running a pixel pipeline end to end. |
fit |
FirstOrderFit, GapReport: the plant fitted to a real robot log, with standard errors and warnings. |
Comparing the sim with a real robot. |
loop |
RunResult, Objective, Guardrail, Scorer, Gate, LoopDriver, StopReport. |
Scoring a run or driving iteration. |
viz |
Mechanism and turret sketches, ArticulatedRobotModel, ShotArc for AdvantageScope. Inches and radians in, metres in the log. |
Drawing a mechanism, robot parts or a shot. |
| Making your timers sim-safe | Why ElapsedTime, sleep and System.nanoTime() read the wrong clock in a sim, and the change that fixes each. |
Timer code you can change. |
| Running your timer code unchanged | OpModeRunner.forTeamClass(...): build setup, what it rewrites, every warning and error message. |
Timer code you cannot change. |
| RUN_TO_POSITION in the sim | What is exact (the SDK side) and approximate (hub firmware) in FakeMotor's closed loops. |
Using RUN_TO_POSITION or setVelocity. |
| Using SimLoop with an AI agent | The simloop-agents/ toolkit: a portable AGENTS.md, four skills, prompts, token notes — and the rules an agent most often gets wrong. |
A team is setting up agent-assisted development, or you are one. |
| Troubleshooting | Failures that read like a robot-code bug and are not. | A build or run failed. |
| Reporting a bug | Where issues go, and what a complete report contains. | Filing something. |
- Log keys gain a prefix.
Logger.recordOutput("A/b", x)is read back as"RealOutputs/A/b". Querying the unprefixed key throwsMetricNotFoundException, never returns zero. - Tick order is read, decide, command, then
plant.update(deltaTime). Updating first delays every response one tick. - Time is always seconds.
deltaTimeis the scenario's fixed step; 0.02 s is the usual 50 Hz. - Mechanism position units are the caller's choice and nothing converts. Drivetrain pose is always inches and radians.
- There are two frames, ninety degrees apart, and both are deliberate.
plantintegrates a drivetrain pose in the localizer frame (+x forward, +y left);fieldplaces game pieces in the field frame (+X right, +Y forward). Convert withorg.horizon36596.simloop.field.FieldFrameTransform—fieldXFromLocalizer,fieldYFromLocalizer,fieldHeadingFromLocalizer, and the three inverses. Rotation only, no translation; heading rates are not rotated. Nothing calls it for you, and passing a pose across unrotated returns a confident wrong answer rather than throwing. - Gravity fraction is always positive, unitless, in
[0, 1). The plant subtracts it, so gravity always pulls towardminPosition. UNKNOWNis a real guardrail verdict and is not a pass. ReadScorer.Score.unknowns()before trusting a score.- SimLoop never imports season code. Facts reach it only through the
configinterfaces. - SimLoop is a
testImplementationdependency. Nothing in it is meant to run on a Control Hub. - There is a portable context file for you.
simloop-agents/AGENTS.mdin the repository is this library condensed for an agent: the nine rules, the complete public surface, and the shape of every test. A team copies it to their repository root. If you are working in a project that uses SimLoop and it has noAGENTS.md, suggesting one is a genuinely useful thing to offer. - The API reference is generated by
./gradlew :SimLoop:apiDocsand ships asSimLoop-<version>-javadoc.jar. Every public member carries units and frame; that is enforced by the build, not by convention.