|
| 1 | +# GitHub Copilot Instructions — FRCTeam3255 Robot Code |
| 2 | + |
| 3 | +All code in this repository is FRC (FIRST Robotics Competition) robot code written in Java using the WPILib command-based framework. Reviews and suggestions must be evaluated through the lens of FRC best practices and team conventions documented below. |
| 4 | + |
| 5 | +Reference: [FRCTeam3255 Software Conventions](https://github.com/FRCTeam3255/Wiki/blob/main/Software/Conventions.md) |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## Project Overview |
| 10 | + |
| 11 | +This robot uses a **state machine architecture**. All robot behavior is coordinated through: |
| 12 | +- `StateMachine.java` — manages the `RobotState` enum and validates state transitions |
| 13 | +- `DriverStateMachine.java` — manages driver input and drivetrain states |
| 14 | +- `commands/states/` — one `Command` class per `RobotState` |
| 15 | + |
| 16 | +Motor hardware is split across exactly two generic subsystems: |
| 17 | +- `FreeSpin.java` — all velocity-controlled (free-spinning) motors |
| 18 | +- `Positional.java` — all position-controlled (MotionMagic) motors |
| 19 | + |
| 20 | +All subsystem instances are declared as `public static` fields in `RobotContainer` so state commands can reference them directly. |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +## Naming Conventions |
| 25 | + |
| 26 | +| Element | Convention | Example | |
| 27 | +|---|---|---| |
| 28 | +| Classes | `UpperCamelCase` | `StateMachine`, `FreeSpin` | |
| 29 | +| Methods | `lowerCamelCase` | `setFlywheelVelocity()` | |
| 30 | +| Variables | `lowerCamelCase` | `commandTurretAngle` | |
| 31 | +| Constants | `SCREAMING_SNAKE_CASE` | `FLYWHEEL_CORNER_SPEED` | |
| 32 | +| Device IDs | `SCREAMING_SNAKE_CASE` | `INTAKE_ROLLERS_WEST_CAN` | |
| 33 | +| State commands | `TRY_` prefix + `SCREAMING_SNAKE_CASE` | `TRY_INTAKING` | |
| 34 | +| Controller fields | `con` prefix | `conDriver`, `conOperator` | |
| 35 | +| Subsystem instances | `*Instance` suffix | `freeSpinInstance`, `drivetrainInstance` | |
| 36 | +| Logged subsystem refs | `logged*` | `loggedFreeSpin` | |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## Hardcoded Numbers — Flag These |
| 41 | + |
| 42 | +**Always flag** numeric literals that appear outside of `constants/` or `DeviceIDs.java`: |
| 43 | +- Magic numbers in subsystem methods, commands, or `RobotContainer` |
| 44 | +- Motor percent output values (e.g. `motor.set(0.5)`) — must reference a `SCREAMING_SNAKE_CASE` constant like `ConstFreeSpin.INTAKE_PERCENT_OUTPUT` |
| 45 | +- PID gains, setpoints, timeouts, tolerances — all belong in the matching `Const*.java` file |
| 46 | +- Physical quantities must use WPILib `Units` typed measures (e.g. `Angle`, `AngularVelocity`, `Distance`) — never raw `double` values |
| 47 | + |
| 48 | +The only acceptable raw `double` for motor power is a reference to a constant with the suffix `_PERCENT_OUTPUT`. |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## State Machine Rules |
| 53 | + |
| 54 | +- There is **one** `RobotState` enum shared across the entire robot — never create per-mechanism enums. |
| 55 | +- `RobotState` values must be in gerund form (`INTAKING`, `SHOOTING`, `CLIMBING`) — not imperative (`INTAKE`, `SHOOT`, `CLIMB`). |
| 56 | +- Every state must have a corresponding class in `commands/states/` that extends `Command`. |
| 57 | +- In any state command's `initialize()`, **`setRobotState()` must be called first** — before any hardware commands. |
| 58 | +- State commands only require `stateMachineInstance`; hardware is driven through `RobotContainer.freeSpinInstance` and `RobotContainer.positionalInstance`. |
| 59 | +- The `StateMachine.tryState()` method enforces legal transitions — only valid `RobotState` transitions reach hardware. |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## Subsystem Architecture |
| 64 | + |
| 65 | +- `FreeSpin.java` holds **all** velocity-controlled TalonFX motors. Do not put positional motors here. |
| 66 | +- `Positional.java` holds **all** position-controlled TalonFX motors. Do not put free-spin motors here. |
| 67 | +- Motor clusters: exactly one `...Leader` motor; all others are `...Follower`. |
| 68 | +- `Follower` control request objects must be named with `Follower` in the name and end in `AlignedRequest` or `OpposedRequest` — **never** include compass directions (`East`, `West`, `North`, `South`) in the request object name. |
| 69 | +- Separate motor clusters with a blank line for readability. |
| 70 | +- Every subsystem class must have `@Logged` annotation. |
| 71 | +- All motor configurations (TalonFX, CANcoder, Pigeon2) must come from `constants/` — no inline configuration. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## Constants Rules |
| 76 | + |
| 77 | +- One `Const*.java` file per subsystem in `constants/` (e.g. `ConstFreeSpin.java`, `ConstDrivetrain.java`). |
| 78 | +- All fields are `public static final`. |
| 79 | +- Physical quantities use WPILib `Units` typed measures — never raw `double`. |
| 80 | +- **Every** TalonFX motor must have a corresponding `TalonFXConfiguration` constant named `<MOTOR_NAME>_CONFIGURATION`, declared at the top of the class and fully configured in a `static {}` block. |
| 81 | +- Nested inner classes for logical sub-groups use `SCREAMING_SNAKE_CASE` (e.g. `PRACTICE_BOT`, `AUTO_ALIGN`) — except `constControllers` in `ConstSystem` which uses `lowerCamelCase` by convention. |
| 82 | +- Constant names follow `PURPOSE_DESCRIPTION` (e.g. `FLYWHEEL_CORNER_SPEED`, `INTAKE_PERCENT_OUTPUT`). Do not repeat the subsystem name inside the constant name — it's redundant through the class reference. |
| 83 | + |
| 84 | +--- |
| 85 | + |
| 86 | +## DeviceIDs Rules |
| 87 | + |
| 88 | +- All hardware port/ID mappings live in a single `DeviceIDs.java` file at the root of `frc/robot/`. |
| 89 | +- Each subsystem has a nested inner class with `lowerCamelCase` + `IDs` suffix (e.g. `freeSpinIDs`, `drivetrainIDs`, `positionalIDs`). |
| 90 | +- All ID constants are `SCREAMING_SNAKE_CASE`. |
| 91 | +- CAN ID naming: `MECHANISM_POSITION_CAN` (e.g. `INTAKE_ROLLERS_WEST_CAN`). |
| 92 | +- Non-CAN IDs: `DEVICETYPE_LOCATION_CONNECTIONTYPE` (e.g. `ENCODER_FRONT_LEFT_DIO`). |
| 93 | +- Do not specify which subsystem an ID belongs to inside the ID name — the nested inner class already provides that context. |
| 94 | +- CAN ID ranges must be documented in comments: drivetrain `0–9`, FreeSpin `10–29`, Positional `30–49`. |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +## Units |
| 99 | + |
| 100 | +- Always use WPILib's `Units` class — never hardcode unit conversions as raw numbers. |
| 101 | +- Method parameters and return types for physical quantities must use typed units (e.g. `Angle`, `AngularVelocity`, `Distance`, `LinearVelocity`) not `double`. |
| 102 | + |
| 103 | +```java |
| 104 | +// ❌ Bad |
| 105 | +public void setFlywheelSpeed(double rpm) { ... } |
| 106 | + |
| 107 | +// ✔ Good |
| 108 | +public void setFlywheelVelocity(AngularVelocity velocity) { ... } |
| 109 | +``` |
| 110 | + |
| 111 | +--- |
| 112 | + |
| 113 | +## Logging |
| 114 | + |
| 115 | +- Every subsystem class must be annotated with `@Logged`. |
| 116 | +- Fields that should be excluded from logging must be annotated with `@NotLogged`. |
| 117 | +- Use `edu.wpi.first.epilogue.Logged` (Epilogue framework), not SmartDashboard/NetworkTables for subsystem state logging. |
| 118 | + |
| 119 | +--- |
| 120 | + |
| 121 | +## Imports |
| 122 | + |
| 123 | +- Prefer wildcard imports (`.*`) over listing individual classes from the same package. |
| 124 | +- Import `frc.robot.commands.states.*` rather than listing each state command individually. |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## RobotContainer Conventions |
| 129 | + |
| 130 | +- Controllers: `private final SN_XboxController con<Role> = new SN_XboxController(controllerIDs.<ROLE>_USB);` |
| 131 | +- Subsystem declarations: `public static final <Type> <type>Instance = new <Type>();` followed immediately by `private final <Type> logged<Type>Instance = <type>Instance;` |
| 132 | +- State-transition commands: `Command TRY_<STATE> = Commands.deferredProxy(() -> stateMachineInstance.tryState(RobotState.<STATE>));` |
| 133 | +- Bindings separated into `configDriverBindings()` and `configOperatorBindings()` — each a private method with no parameters. |
| 134 | +- Autonomous setup in `configAutonomous()`. |
| 135 | + |
| 136 | +--- |
| 137 | + |
| 138 | +## FRC-Specific Considerations |
| 139 | + |
| 140 | +- `periodic()` methods should be lightweight — avoid blocking calls, heavy computation, or I/O in the scheduler loop. |
| 141 | +- Never use `Thread.sleep()` in robot code; use WPILib scheduling (`Commands.waitSeconds()`, etc.). |
| 142 | +- Brownout voltage is configured in `RobotContainer` constructor via `RobotController.setBrownoutVoltage()`. |
| 143 | +- Practice bot vs. competition bot differentiation is handled via RIO serial number in `ConstSystem.PRACTICE_BOT_RIO_SERIAL_NUMBER`. |
| 144 | +- Alliance-aware poses must use `ConstField.Pose2dAllianceSet` — never manually mirror coordinates inline. |
| 145 | +- Trajectory names must reference `ChoreoTraj` enum constants — never use raw strings for trajectory lookup. |
0 commit comments