Architecture
Main Loop Philosophy
The firmware is structured so that all subsystems run concurrently without blocking.
The loop performs a consistent pipeline:
- Read controller inputs
- Decide feedback states (buzzer/rgb)
- Execute feedback updates (millis-based)
- Compute drive command (throttle/steering mixing)
- Map drive command to motor driver PWM pins
- Write PWM to motors
Why no delay()
Using delay() would freeze:
- controller responsiveness
- smooth motor control
- feedback timing accuracy
Instead, timing is implemented with:
- timestamps (lastMs)
- intervals (intervalMs)
- state variables (step counters / toggles)
Subsystems
Input
Reads controller state into a ControllerInput struct (snapshot).
Drive
Converts input → DriveCommand → motor PWM outputs via:
- deadzones
- mixing
- clamping
- H-bridge mapping
Feedback
Two independent non-blocking state machines: - RGB: blink patterns driven by toggles and counters - Buzzer: priority state machine that prevents multiple writers to BUZ pin