Skip to content
ZOGWORKPublic

About

FTC BIOBUZZ 2026-27 robot code: MainHORS teleop + 2-tip auto (Zenith + SimLoop + Pedro v3)

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

212 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BioHORS

FTC robot code for the 2026-27 BIOBUZZ season, built on the PedroPathing Quickstart v3.0.2 (PedroPathing v3, FTC SDK 12.0.0). Seeded from HORS-Pedro; the MainHORS control scheme carries over, the old code does not.

Robot: mecanum drive with Pinpoint odometry (2 pods), 2 intake motors, 2 independent shooters (pollen and nectar, one goBILDA 5000-series 6000 RPM motor each, same spin direction, different speeds), 2 independent gate servos (one per shooter). No turret: aiming turns the whole robot.

The MainHORS teleop with odometry aim, and a Zenith-planned 2-tip pollen auto, both tested in SimLoop.

OpModes

OpMode File What it does
MainHORS TeleOp teamcode/teleop/MainHorsTeleOp.java The teleop: MainHORS controls plus odometry aim (see below)
Two tip teamcode/zenith/generated/TwoTipAuto.java (generated) The 2-tip pollen auto, played from autos/two-tip.auto.json by Zenith (see below)
Choose Alliance teamcode/opmodes/ChooseAlliance.java Run before the auto: dpad left = RED, dpad right = BLUE
Shooter Tuner teamcode/tuning/ShooterTuner.java Measures each shooter's feedforward (power sweep) and P (search), prints PIDF to paste into MechanismConstants. Robot on blocks, no pollen
Tuning (Quickstart) teamcode/pedro/Tuning.java + procedures/ PedroPathing tuners, including the Pinpoint Tuner

Hardware map (must match the Robot Controller config exactly)

Name Device Notes
frontLeft, backLeft DcMotor Drive, FORWARD
frontRight, backRight DcMotor Drive, REVERSE
intakeLeft, intakeRight DcMotor Intakes, run together
shooterRight DcMotorEx Pollen shooter (confirmed: right side, top-down with the intake up)
shooterLeft DcMotorEx Nectar shooter (confirmed: left side)
gateRight Servo Pollen gate (confirmed)
gateLeft Servo Nectar gate (confirmed)
pinpoint GoBildaPinpointDriver Pinpoint odometry computer (2 pods), used by the Pedro localizer

Shooter/gate names, directions, and tuning values live in teamcode/subsystems/MechanismConstants.java.

Teleop controls (MainHORS TeleOp; gamepad2 mirrors the mechanism buttons)

Control Action
Left stick Drive (forward / strafe)
Right stick X Turn (overridden while aiming)
Left trigger (hold) Aim: turn the robot to face our hive's cell on this half of the field, and spin both shooters up (no dpad down needed; a volley under way keeps them up after you let go)
Right bumper (hold) Slow mode, 0.45x. While aiming: each press nudges the aim 1° right instead
Right trigger Intake in (a stalled intake reverses for 0.3 s on its own; the Fire line says INTAKE JAM. After 3 reverses that do not clear it the intake stops: INTAKE JAMMED: clear by hand, until you let go)
Y Volley: spins both shooters up; once they are at speed (or after 2 s if they never get there) both gates open and the intake runs for 1 s, then the gates close and the intake stops. No pose or aim check; it does not aim. B and the intake trigger are locked out while it runs. Y again cancels. Fire line: Y SEQ
Dpad down Toggle both shooters on/off, each at its own target (start OFF), to keep them spinning without aiming
Dpad left / right Both shooters' target RPM − / +, the same 50 rpm each press. Gamepad1 only: gamepad2's dpad left / right do nothing
Left bumper While aiming: each press nudges the aim 1° left. Nothing otherwise. The nudge (up to ±10°) stays until an X reset; the Pose line shows it
A (hold) Outtake: both intake motors run out. Wins over right trigger; locked out while the Y volley runs
B Toggle both gates open / closed. No pose, aim or speed check: you decide. The Fire line still says READY, or NOT READY: ... with the reason, so you know whether the shot would score
X (hold 0.5 s) Reset the pose (wipes Pinpoint drift): push the robot into your alliance's corner past the loading zone (RED: north-west, BLUE: south-east), back flat on the side wall and its side flat on the end wall, intake facing the field, then hold X until the pad rumbles. A tap does nothing
Dpad up (gamepad1 only) Flower bar down / stowed. It starts stowed (0.80); the first press puts it down (0.0), the next stows it. The right servo is reversed, so it gets 1 minus the left's number. While it is down the drive is capped at 0.6x (BAR DOWN: slow)
Gamepad2 left trigger (hold) Gamepad2's only flower bar control: held, the bar goes down; let go, it goes back up. Gamepad2's dpad up does nothing

Before PLAY, pick the alliance: dpad left = RED, dpad right = BLUE. If an auto ran first, its alliance and final pose are picked up automatically (the SDK blackboard), once, and only if the auto saved the pose under a minute ago; if not, the teleop assumes it starts at the auto's park spot (back to the west wall by the loading zone, intake facing the field; mirrored for BLUE), and INIT telemetry says why.

Driving display, extras on the Fire line: INTAKE JAM: reversing, LOW BATTERY 11.2 V (under 11.5 V for a second), and ENDGAME n s counting down the last 30 s. The gamepads rumble three short blips as the endgame starts and once, long, 10 s before the end. A shooter whose encoder reads nothing while it is pushed shows ENCODER? (no speed reading) and runs on its feedforward alone instead of winding up to full power; its gate stays shut and the other shooter fires alone (POLLEN FAULT: nectar only, with a long left-side rumble). A backwards encoder (negative rpm while pushed forward) shows ENCODER REVERSED? and is handled the same way. Also on the Fire line: GATES OPEN while they are, and SLOW LOOP n ms when the loop averages over 40 ms. The Loop line ends with where the last loop went: odo (the Pinpoint read), mech (the hubs' encoder read and both shooter loops) and drive (the four drive writes), in ms. A pose off the field or one that jumped further than the robot can drive in a loop is INVALID (aim off) until X resets it.

Live tuning (Panels): every class with tuning numbers is @Configurable. Connect the laptop to the robot's Wi-Fi and open Panels in a browser (http://192.168.43.1:8001); the values change on the robot as you edit them, and go back to the code's values when the robot restarts. Copy a value you want to keep into the code.

Idle and trims: idle is OFF for now (SHOOTER_IDLE_ENABLED = false): unasked, the flywheels stand still. Switched on, with neither dpad down nor aim asking for them, both flywheels idle at 800 rpm (IDLE), so a spin-up starts part way; idle never counts as ready to fire. The rpm trims carry over to the next teleop; press back during INIT to clear them.

INIT check (teleop and both autos): a pass/fail list before PLAY: Pinpoint READY, battery at 12.5 V or more, both shooter encoders at rest; the teleop adds whether an auto pose is waiting.

Failsafes in the autos: if the Pinpoint stops reporting READY mid-route (5 loops), or is not READY 1 s after PLAY, the auto halts: drive stopped, mechanisms off, gates shut (AUTO HALTED). At the spin-up timeout a volley fires only if the flywheel is at 80 % of its target or more; otherwise it is skipped with the pollen kept (SHOOTER never reached speed). The hand-written state machine auto also watches the clock: still at the garden at 20.5 s it leaves with what it has, and reaching the last volley at 25.2 s or later it skips the volley and parks (LATE). The Zenith auto runs its steps in a fixed order, so it has no such cutoff.

Aim. No camera and no turret: holding the left trigger turns the whole chassis to face the hive cell on the robot's half of the field (north cell when y > 0, south when y < 0, with 2 in of hysteresis at the line), from the Pinpoint pose and the hive's fixed field coordinates (BIOBUZZ field file: RED hive pivot (-12.75, 0), BLUE (+12.75, 0), cell centres 9.264 in either side along y). A launch only scores from the up cell's own quarter, so the driver picks the cell by where they drive; there is no goal toggle. The driver keeps forward/strafe; yaw gets priority over translation, and a feedforward on the bearing rate keeps the aim on target while strafing. If the Pinpoint is not READY or the pose is not a number, aim falls back to manual turn and telemetry shows POSE INVALID. Telemetry always shows the alliance, target cell, aiming on/off, heading error and pose.

The 2-tip auto (Zenith)

autos/two-tip.auto.json, planned with Zenith and played on the robot by Zenith's runtime through the Pedro v3 follower and the named commands in zenith/BioHorsCommands.java. Pollen only, 12 pollen in 3 volleys of 4 (RED described):

  1. Score the 4 preload from scoreSouth into the up cell, on the 3 staged nectar: tip 1.
  2. Go round the west of the hive frame to flower1 (north wall), take its 4 with the flower bar down, score them from scoreNorth.
  3. Sweep the RED garden row along the south wall (bar stowed), drive back and score from scoreNorth: tip 2. Park.

The two-tip auto, RED The two-tip auto, BLUE

One OpMode per alliance: pick the one for your side. "Two tip" runs autos/two-tip.auto.json (RED); "Two tip (BLUE)" runs autos/two-tip-blue.auto.json, Zenith's mirror of the RED file (BIOBUZZ is point-symmetric), written by node tools/mirror_auto.mjs. The Zenith autos ignore Choose Alliance (it is still used by the state-machine auto and by the teleop when no auto ran). When the auto stops, its alliance and pose go to the teleop's aim. After any change to the RED auto or autos/waypoints.json, re-run node tools/mirror_auto.mjs, then npx zenith deploy and npx zenith codegen two-tip-blue; BlueAutoMirrorTest fails until you do.

Editing it: npm install (pins the Zenith CLI and MCP in package.json), then use the Zenith MCP server (.mcp.json) or npx zenith validate|estimate|render|deploy|sim ... --json. The build-auto skill (.claude/skills/build-auto/, with references/robot.md for this robot) is the workflow. Never edit TeamCode/src/main/assets/autos/ or zenith/generated/: npx zenith deploy writes them. No mid-path markers: Zenith v0.1.2's marker runner needs a Pedro method Pedro 3.0.2 lacks.

Simulation (SimLoop)

./gradlew :TeamCode:testDebugUnitTest (Windows: .\gradlew.bat ...) runs the real OpModes on a laptop against fake hardware, in TeamCode/src/test/java/org/firstinspires/ftc/teamcode/sim/:

  • BioHorsSim: this robot's fake devices and physics (drive, Pinpoint, shooters, gates, intake).
  • MainHorsTeleOpSimTest: the teleop (drive, slow mode, aim, goal switch, aim while strafing, Pinpoint-fault fallback, BLUE, shooters, gates, intake, determinism).
  • ZenithAutoMatchTest + BiobuzzMatch + TracedZenithAuto: the deployed auto as a BIOBUZZ match, stopped at 30 s like the field: RED twice (identical logs) and BLUE once. It checks 16 pollen and 2 tips in AUTO, every step in order, no structure contact, strafing under 20 % of the driving, and the robot's belief against the sim's truth. npx zenith sim two-tip runs the same test.
  • LiveDriveTest: the live-controller session's plumbing (LiveDrive, LiveDriveSession, below) with scripted input: input reaches the teleop, a recorded session replays to the same log.

Every sim number is a placeholder until measured (docs/TUNING.md), so the sim proves the code's logic and wiring, not the real robot's timing.

RLOGs and Zenith traces land in TeamCode/build/sim/ (gitignored; re-run the tests to regenerate).

Watch a run on the 3D field. Open TeamCode/build/sim/two-tip-red.rlog (or two-tip-blue.rlog, teleop-aim.rlog) in AdvantageScope, open a 3D Field tab (or 2D Field) and pick 2026-2027 Field. From RealOutputs/Field, drag:

  • Robot onto the field: the robot's true pose (choose a robot model, e.g. FTC drive base);
  • RobotBelief and set it to Ghost: where the robot thinks it is (match runs);
  • Pollen and set it to Game Piece → Pollen: the garden line, the flower columns, the 4 aboard, each launch flying into the hive, the pollen in the cells, and each tip's spill.

Press play. Poses are logged in AdvantageScope's FTC "Center/Rotated" frame (metres), converted from the field frame the code uses by sim/AdvantageScopeFrame. Match/scored, Match/tips, Shooter/pollenRpm plot on a Line Graph.

Drive it yourself with a controller. Plug a USB game controller (Xbox, Logitech F310 in X mode, PS4/PS5) into the laptop and run

.\gradlew.bat driveSim

to drive the teleop on the simulated robot and field in real time, with a top-down window and the Driver Station telemetry. Hold BACK + START to end early. Each session is recorded under TeamCode/build/sim/live/ as an RLOG for AdvantageScope plus the controller input, which .\gradlew.bat driveSim -Preplay=latest replays exactly. Options and details: docs/LIVE_DRIVE.md.

Nothing is tuned yet

The full brief, item by item, is docs/TUNING.md.

Every tuning number in the code carries a provenance label: SPEC (from a spec sheet), PLACEHOLDER (made up so the code runs), or NEEDS MEASUREMENT. None are measured. Do not treat any as real.

  1. Shooters (subsystems/MechanismConstants.java): each shooter has its own target RPM, PIDF, tolerance, and feedforward. Gains are placeholders. ticksPerRev = 28 and feedforward max = 2800 ticks/sec are the goBILDA 6000 RPM motor spec. ticksPerRev counts per flywheel revolution, so 28 only holds if the flywheel is direct-driven (1:1); with a belt/gear ratio, multiply it by the ratio. The 2800 ticks/sec is the motor encoder's free speed and does not change with the ratio. Shooter motor directions and which motor is pollen still need verifying on the robot.
  2. Gates (subsystems/MechanismConstants.java): open/closed position per gate. Both start at the old shared placeholders (0.67 / 0.485).
  3. Pinpoint (pedro/Constants.java): pod offsets and directions. Run the Quickstart's Pinpoint Tuner on the robot.
  4. Aim (aim/AimController.java): kP, yaw cap, minimum yaw, on-target tolerance, turn rate at full yaw, and which way the shooter fires (SHOOTER_FACING_OFFSET_RAD). Teleop default start pose (teleop/MainHorsTeleOp.java) when no auto ran first.
  5. Drive shaping, intake power, Foresight gains, auto timing: placeholders, labelled in their files.

Building

Open in Android Studio (Narwhal 3 Feature Drop or later) and build like any FTC SDK project. The PedroPathing dependencies (revhub 3.0.2, tuning 1.0.3) are in build.dependencies.gradle.

Horizon's tools

Zenith (beta) and SimLoop (alpha) are by Horizon (FTC 36596) and are early; they are looking for testers and contributors. Zenith: https://zenith.horizon36596.org · SimLoop: https://github.com/Horizon-36596/simloop · Example robot: https://github.com/Horizon-36596/Horizon-Library-Examples · Docs: https://libraries.horizon36596.org · Discord: https://discord.gg/p2D3JpM4f6 · Release video: https://youtu.be/NFww9Mt-ZR4

Workflow

Work on branches and open PRs; Greptile reviews every PR. Do not push to main directly.

About

FTC BIOBUZZ 2026-27 robot code: MainHORS teleop + 2-tip auto (Zenith + SimLoop + Pedro v3)

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages