Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
16deab3
Changes made to the auto shoot and dashboard
SAKETH11111 Mar 14, 2026
3ca1bf4
Enhance shooter and turret functionality with new auto mode and manua…
SAKETH11111 Mar 14, 2026
68d90e9
Refactor shooter and turret logic for improved functionality, includi…
SAKETH11111 Mar 15, 2026
baf5f0c
Add shooter telemetry baseline
SAKETH11111 Mar 15, 2026
9966cbf
Add shot calculator skeleton
SAKETH11111 Mar 15, 2026
f6ea822
Refactor shooter targeting ownership
SAKETH11111 Mar 16, 2026
7b1b85d
Fix shooter readiness gate
SAKETH11111 Mar 16, 2026
e0b0091
Clean up turret geometry and wrap handling
SAKETH11111 Mar 16, 2026
71b7bad
Remove turret wrap test file
SAKETH11111 Mar 16, 2026
c7684ea
Restore track parity and drop local turret test
SAKETH11111 Mar 16, 2026
fde46a0
Add SWM tracking-only turret solve
SAKETH11111 Mar 16, 2026
32a7700
Add rotor subsystem and integrate with shooter system
SAKETH11111 Mar 16, 2026
e88c390
Refactor shooter and turret subsystems for improved control and perfo…
SAKETH11111 Mar 16, 2026
f79c17a
Refactor RobotContainer and Shooter subsystems
SAKETH11111 Mar 19, 2026
89f3d12
Tune rotor behavior and clean shooter controls
SAKETH11111 Mar 19, 2026
47b9af4
integration of Motion Magic
SAKETH11111 Mar 19, 2026
f5f7db8
Add chooser-driven auto dashboard
SAKETH11111 Mar 19, 2026
993922b
clean up warnings
CanineSatsuma6 Mar 19, 2026
f7da2ea
Refactor Intake and Shooter Subsystems
SAKETH11111 Mar 19, 2026
325999d
Auto maybe?
SAKETH11111 Mar 20, 2026
b084bfd
changes to make the auto work
SAKETH11111 Mar 20, 2026
a419ffa
left bump path update
CanineSatsuma6 Mar 20, 2026
50c28a4
switch to Megatag1 for pose estimation
CanineSatsuma6 Mar 21, 2026
9eebd0c
clean up autos.java formatting, but don't change behavior
CanineSatsuma6 Mar 21, 2026
d792e97
pull starting pose from path rather than from start if driving
CanineSatsuma6 Mar 21, 2026
0d53ad9
draw trajectories
CanineSatsuma6 Mar 21, 2026
7375101
add logging of path poses
CanineSatsuma6 Mar 21, 2026
db0bcf1
reject vision estimates if no tag is within 10 feet
CanineSatsuma6 Mar 21, 2026
4a109cf
disable vision pose correction while shooting
CanineSatsuma6 Mar 21, 2026
ea1fb4f
WIP for auto
CanineSatsuma6 Mar 22, 2026
3a0ba12
updated standard deviasions for auto and teleop
CanineSatsuma6 Mar 24, 2026
12511d7
Formatted code using spotless.
github-actions[bot] Mar 25, 2026
6d93340
Update trajectories and auto commands
SAKETH11111 Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions documentation/shooter-turret-cheat-sheet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Right now, the most important thing to understand is that the shooter code is not one single blob. It is split into three layers on purpose. `Shooter` is the coordinator that owns the top-level state machine and decides when the robot is allowed to feed a note. `TurretDirector` is the math layer that figures out what shot we want right now. `Turret` is the actuator/sensor layer that reads the live turret angle and physically drives the turret to the requested angle. If those three responsibilities stay mentally separate, the code becomes a lot easier to reason about.

```mermaid
flowchart LR
A["Driver / Operator command"] --> B["Shooter"]
B --> C["TurretDirector"]
C --> D["ShotSolution"]
D --> E["Turret target angle"]
D --> F["Flywheel speed target"]
B --> G["Feed gating"]
E --> H["Turret"]
F --> I["Flywheel"]
G --> J["Feeder + Rotor"]
```

## How the pieces fit together

`Shooter` exists because shooting is not just “point and spin.” It has to coordinate the turret, the flywheel, the feeder, the rotor, and all of the readiness conditions that decide whether we are actually allowed to fire. That is why `Shooter` owns the high-level states like `Idle`, `Preparing`, `Ready`, `Firing`, `Manual`, and `TrackingOnly`. It is the part of the system that answers questions like “are we trying to shoot right now,” “should the feeder be running,” and “what should happen if readiness drops out in the middle of a shot.”

`TurretDirector` exists because shot calculation is a different problem from actuation. Its job is to look at the current robot state, the selected shot mode, the target geometry, and any active adjustments, and then condense that down into one `ShotSolution`. That solution includes the turret angle we want, the effective shot distance, and enough context for the rest of the shooter stack to act on it. Static aiming, moving-shot aiming, pass aiming, vision trim, and the empirical drift correction all live there because those are all part of “what shot are we trying to take,” not “how do we move the turret motor.”

`Turret` exists because it should be the only place that really cares about the live potentiometer angle, wrap handling, PID output, and lined-up reporting. In other words, `TurretDirector` should not need to know how the turret motor is controlled, and `Shooter` should not need to know how the potentiometer reading becomes a motor command. That separation is what lets us debug the system in chunks instead of trying to hold the entire subsystem in our heads at once.

## A good debugging mental model

The fastest way to debug this subsystem is to ask where the mistake first appears. If the **desired angle itself is wrong**, then the problem is usually in `TurretDirector`, because that means the shot math produced the wrong answer. If the **desired angle looks correct, but the turret is physically somewhere else**, then the problem is usually in `Turret`, because the actuation layer is not getting to the requested setpoint. If the **turret is aimed correctly and the flywheel is up to speed, but the robot still will not fire**, then the problem is usually in `Shooter`, because the feed gating or top-level state machine is what decides whether the feeder and rotor are allowed to run.

That one mental split is probably the most useful thing to keep in mind while reading the code or looking at logs.

## What happens during a normal shot

When the driver presses the normal shoot button, `Shooter.shoot()` requests `ShotMode.Track` and moves the subsystem into `Preparing`. From there, `Shooter.periodic()` keeps asking `TurretDirector` for an updated `ShotSolution`. That `ShotSolution` is used to command a turret angle and a flywheel speed. While this is happening, `Shooter` is also checking whether the various readiness gates are true. Those gates answer questions like whether the shot solution is valid, whether the turret is lined up closely enough, whether the flywheel is at speed, and whether any moving-shot constraints are satisfied. Once those conditions are satisfied, the subsystem becomes effectively ready to fire, and if auto-shoot is enabled, it transitions into the firing path. The feeder and rotor only stay on while those readiness checks continue to pass. If readiness drops, the subsystem falls back out of firing and returns to preparing.

That is why `Shooter` exists as a coordinator. The robot needs one place that can say, “yes, the math looks good, the turret is there, the flywheel is ready, and we are now allowed to feed.”

## Why `TrackingOnly` exists

`TrackingOnly` is there because aiming and firing are not the same problem. Sometimes we want to verify the turret math, the alignment behavior, or the shoot-while-moving solve without feeding a note. `TrackingOnly` keeps the targeting stack alive, keeps producing fresh shot solutions, and keeps commanding the turret, but it intentionally does not run the feeder or rotor. That makes it the safest state to use when we want to validate whether the robot is leading the target correctly or whether the turret is hunting around a setpoint.

## Where shoot-while-moving fits

Shoot-while-moving does not replace the shooter subsystem. It only changes the shot calculation that `TurretDirector` performs. `Shooter` still owns whether moving-shot math should be active, and it still owns whether we are actually allowed to feed once that moving-shot solution exists. In practice, that means SWM lives in two places conceptually. The math lives in `TurretDirector`, because that is where the lead angle and effective shot distance are calculated. The readiness logic lives in `Shooter`, because that is where we decide whether the moving-shot solution is trustworthy enough to actually fire from.

This is also why SWM can feel confusing if you only look at one class. The aiming math and the feed decision are intentionally split between two layers.

```mermaid
flowchart TD
A["ShotMode.Track requested"] --> B["Shooter decides whether SWM is active"]
B --> C["TurretDirector.calculate(..., useMovingShotMath)"]
C --> D["Static track solution or moving-shot solution"]
D --> E["Shooter checks feed readiness"]
E --> F["If ready, feeder + rotor run"]
```
2 changes: 1 addition & 1 deletion src/main/deploy/choreo/DepotToOutpost.traj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"waypoints":[
{"x":{"exp":"Depot.x", "val":1.15}, "y":{"exp":"Depot.y", "val":5.9625654220581055}, "heading":{"exp":"Depot.heading", "val":3.141592653589793}, "intervals":21, "split":false, "fixTranslation":true, "fixHeading":true, "overrideIntervals":false},
{"x":{"exp":"1.899867296218872 m", "val":1.899867296218872}, "y":{"exp":"3.7941935062408447 m", "val":3.7941935062408447}, "heading":{"exp":"Depot.heading", "val":3.141592653589793}, "intervals":25, "split":false, "fixTranslation":true, "fixHeading":true, "overrideIntervals":false},
{"x":{"exp":"Outpost.x", "val":0.6543505787849426}, "y":{"exp":"Outpost.y", "val":0.6869499087333679}, "heading":{"exp":"Outpost.heading", "val":3.141592653589793}, "intervals":40, "split":false, "fixTranslation":true, "fixHeading":true, "overrideIntervals":false}],
{"x":{"exp":"Outpost.x", "val":0.6543505787849426}, "y":{"exp":"Outpost.y", "val":0.6869499087333679}, "heading":{"exp":"Outpost.heading", "val":4.71238898038469}, "intervals":40, "split":false, "fixTranslation":true, "fixHeading":true, "overrideIntervals":false}],
"constraints":[
{"from":"first", "to":null, "data":{"type":"StopPoint", "props":{}}, "enabled":true},
{"from":"last", "to":null, "data":{"type":"StopPoint", "props":{}}, "enabled":true},
Expand Down
Loading