A field management system for FRC-style robotics competitions built around a Raspberry Pi with REV Color Sensor V3 hardware. It provides live scoring, match timing, and sensor-based game piece detection with both a pygame display and a web-based overlay.
- Automatic game piece scoring — two REV Color Sensor V3 units detect red and blue game pieces via I2C
- Fullscreen scoring display — built with pygame, shows live scores, match timer, and phase (auto/teleop/pause)
- Web overlay —
display.htmlserved on port 8080 for OBS browser sources or secondary displays - Match state API — JSON endpoint at
/scoresfor external integrations - Simulation mode — run and develop without Raspberry Pi hardware
- Keyboard controls — full match control from the scoring computer keyboard
Everything lives in a single Python file and a static HTML file:
rpi-colorsensor.py— main application containing:ColorSensorV3— I2C driver for the REV Color Sensor V3 (pigpio-based)score_state— shared mutable state between the pygame loop and HTTP serverScoreHTTPHandler/start_http_server— minimal HTTP server on port 8080- pygame main loop — game logic, sensor reading, and display rendering
display.html— transparent web overlay for OBS or browser viewing; auto-connects when served by the FMS
-
Commit and push any changes you've made after testing locally.
-
Press escape with the FMS running to drop yourself into a shell. Then run the following
cd rpi-colorsensor
git pull
rebootThis project uses Nix for the development environment.
-
Enter the dev shell (direnv does this automatically if you have it set up):
nix develop
-
Install Python dependencies (handled by Nix; includes Python 3.12, pygame, and pynetworktables)
Use this for development or testing on any Linux machine:
SIMULATION=True python rpi-colorsensor.pyRuns at 15fps with no pigpio dependency.
Requires the pigpio daemon running and I2C enabled:
sudo systemctl enable --now pigpiod
python rpi-colorsensor.py| Key | Action |
|---|---|
Space |
Start match (auto phase, 15s) / toggle pause during match |
b |
Start match directly in teleop (135s, no auto) |
c |
Clear/reset all scores |
Escape |
Quit |
t / g |
Red score +1 / -1 |
y / h |
Blue score +1 / -1 |
r / f |
Red auto score +2 / -2 (also adjusts total) |
u / j |
Blue auto score +2 / -2 (also adjusts total) |
e / d |
Red penalty +1 / -1 |
i / k |
Blue penalty +1 / -1 |
When started with Space:
- Auto — 15 seconds
- autoPause — 5 seconds ("Pick Up Your Controller!")
- Teleop — 135 seconds
- Overlay:
http://<host>:8080/servesdisplay.html- Transparent background for OBS compositing (enable "Allow transparency" in the OBS browser source)
- Font sizes scale with viewport width for flexible sizing
- When opened as a local file, prompts for the server IP; when served by the FMS, auto-connects
- API:
http://<host>:8080/scoresreturns match state as JSON with CORS headers
-
Enable I2C:
sudo raspi-config # Interface Options -> I2C -> YesOr manually edit
/boot/config.txt:- Uncomment
dtparam=i2c_arm=on - Add
i2c-devto/etc/modules
- Uncomment
-
Enable pigpio daemon:
sudo systemctl enable --now pigpiod
The 4-pin sensor cable is GND, 3.3V, SDA, and SCL. Connect to Raspberry Pi I2C bus 1:
| Sensor Wire | Pi Pin |
|---|---|
| GND (black) | Pin 6 |
| 3.3V (red) | Pin 1 |
| SDA (white) | Pin 3 |
| SCL (blue) | Pin 5 |
For GPIO/I2C pin reference, see pinout.xyz.
- Sensor 1 — I2C bus 1 (default hardware bus on GPIO 2/3, has 1.8k pull-ups)
- Sensor 2 — I2C bus 0 (requires additional configuration depending on Pi model)
On Raspberry Pi 3B, use software I2C by adding to /boot/config.txt:
dtoverlay=i2c-gpio,bus=6,i2c_gpio_sda=22,i2c_gpio_scl=23
dtoverlay=i2c-gpio,bus=5,i2c_gpio_sda=12,i2c_gpio_scl=13
dtoverlay=i2c-gpio,bus=4,i2c_gpio_sda=8,i2c_gpio_scl=9
dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=4,i2c_gpio_scl=5
On Raspberry Pi 4, additional hardware buses are available:
dtoverlay=i2c3
dtoverlay=i2c4
dtoverlay=i2c5
dtoverlay=i2c6
Note: software I2C buses and buses 3–6 require external pull-up resistors to 3.3V on SDA/SCL.
- Red pieces — detected by Sensor 1 when
r > 0.45andb < 0.3 - Blue pieces — detected by Sensor 2 when
r < 0.4andb > 0.4
Detection is debounced to avoid double-counting.
- Display layout assumes a 1920px wide screen (coordinates are hardcoded)
- Hardware mode runs at ~200fps; simulation mode runs at 15fps
- The HTTP server runs in a daemon thread alongside the pygame main loop