Our robot software is organised around modularity, composability and a clear separation of responsibilities. The team’s Kotlin codebase gives each subsystem its own lifecycle and keeps time-sensitive behaviour within a coordinated control loop.
One component lifecycle
Subsystems share init(), start(), loop() and stop() methods. A component registry lets OpModeBase initialise and update them in a consistent order; bulk caching and unified telemetry help the team observe the robot as a complete system. Dagger 2 provides compile-time dependency injection.
Control at the right moment
Flywheel speed is calculated from encoder deltas, filtered and controlled with PID plus feedforward. Colour sensing is requested when the feed mechanism activates, reducing unnecessary I²C traffic. If all three storage positions cannot be identified reliably, the feed logic falls back to sequential activation.
- Colour-based commands reduce driver workload.
- Pattern-based activation supports MOTIF scoring.
- Field-centric mecanum control, slow mode and intake reversal support teleoperated driving.
Sensors with a purpose
The documented sensor stack includes a REV Through Bore Encoder, odometry pods, a goBILDA Pinpoint computer, REV Color Sensor V3 units and a Limelight 3A camera. Each supports a specific decision: speed feedback, localisation, artifact identification or AprilTag alignment.
What the season taught us
Low loop times matter, and PID coefficients must be revisited when a mechanism or timing changes. Real-world units make control code easier to understand, while subsystem-local tuning constants make the robot easier to maintain.





