8.7 KiB
8.7 KiB
📡 Taekwondo Scoring System – Device Signals & Communication Protocol
Version: 2.0 (Full Device Coverage)
Last Updated: July 2025
Target Developer: Embedded (ESP32) & Android (.NET) Developers
Purpose: Define two-way communication for all battery-powered devices: joysticks, hogu, and headgear
📌 Table of Contents
- 1. Overview
- 2. Device Types
- 3. Communication Model (TCP Full-Duplex)
- 4. Common Device Signals
- 5. Referee Joystick
- 6. Hogu (Trunk Protector)
- 7. Headgear
- 8. OLED Display (128x64, I2C 0x3C)
- 9. Telemetry: Battery & Health Monitoring
- 10. Feedback: Vibration, LED, Buzzer
- 11. Command & Response Format
- 12. ESP32 Code Structure (Modular)
- 13. Android .NET Server Integration
- 14. Best Practices
1. Overview
All battery-powered devices in the system support two-way TCP communication:
- ✅ Send: Sensor data, telemetry, events
- ✅ Receive: Feedback commands, display updates, calibration
- ✅ Device Types:
- Referee Joysticks (4 units)
- Hogu (Trunk Protector) – Red & Blue
- Headgear – Red & Blue
Each device identifies itself with:
DEVICE:NAME=...,TYPE=...,MAC=...
2. Device Types
| Device | Type | Key Features |
|---|---|---|
| Joystick | JOYSTICK |
Button, OLED, vibration, LED, buzzer, battery telemetry |
| Hogu | SENSOR |
Force sensor (FSR), MPU6050 (spinning), OLED, vibration, battery |
| Headgear | SENSOR |
Force sensor, MPU6050, OLED, vibration, battery |
All use ESP32-C3, LiPo battery, and I2C OLED (0x3C).
3. Communication Model (TCP Full-Duplex)
[All Devices] ↔ [Android Tablet: TCP Server (Port 5000)]
- Devices connect to
192.168.4.1:5000(hotspot mode) - First message:
DEVICE:NAME=...,TYPE=...,MAC=... - Subsequent messages: JSON
\n-terminated - Server can send commands at any time
Full-duplex: Send and receive on same connection.
4. Common Device Signals
4.1 Device Identity (Mandatory First Message)
DEVICE:NAME=HOGU_RED,TYPE=SENSOR,MAC=30:85:A9:12:34:56
4.2 Telemetry (Periodic, Every 60 sec)
{
"type": "telemetry",
"device": "HOGU_RED",
"battery_level": 88,
"battery_voltage": 4.02,
"rssi": -65,
"uptime": 3420,
"timestamp": 1712345679000
}
4.3 Command Acknowledgment
{"ack": "vibrate", "time": 1712345679100}
5. Referee Joystick
📥 Outgoing
buttonpresstelemetry
📤 Incoming Commands
vibrate– tactile feedbackbuzz– audible alertled– status indicationdisplay– show textping– liveness check
Example Button Press
{"type":"button","device":"JOYSTICK_CORNER_1","pressed":true,"time":1712345678905}
6. Hogu (Trunk Protector)
📥 Outgoing
6.1 Impact Detection
{
"type": "impact",
"device": "hogu_red",
"force": 850,
"spinning": true,
"time": 1712345678901
}
force: 0–1023 (analog read)spinning: from MPU6050 (rotation > 180°)
6.2 Telemetry
Same as joystick, includes sensor health.
📤 Incoming Commands
| Command | Effect |
|---|---|
vibrate |
Confirm impact registered |
led |
Flash green/red for status |
display |
Show "HOGU RED", battery, status |
calibrate |
Recalibrate force sensor |
ping |
Liveness check |
Example: Calibrate Command
{"cmd": "calibrate", "mode": "zero"}
7. Headgear
📥 Outgoing
7.1 Impact Detection
{
"type": "impact",
"device": "head_blue",
"force": 720,
"spinning": false,
"time": 1712345678903
}
Lower force threshold (safety).
7.2 Telemetry
Same format, sent every 60 sec.
📤 Incoming Commands
| Command | Effect |
|---|---|
vibrate |
Confirm head kick detected |
led |
Status light (e.g., red = fault) |
display |
Show "HEAD BLUE", battery |
ping |
Liveness check |
No
calibrate— headgear is sealed.
8. OLED Display (128x64, I2C 0x3C)
All devices have the same OLED for status and feedback.
8.1 Display Modes
| Device | Normal | Active | Low Battery | Error |
|---|---|---|---|---|
| Joystick | CORNER 1READY |
PRESSED! |
⚠️ BATT: 20% |
NO SIGNAL |
| Hogu | HOGU REDOK |
IMPACT! |
⚠️ BATT: 15% |
SENSOR FAULT |
| Headgear | HEAD BLUEACTIVE |
HIT DETECTED |
⚠️ BATT: 10% |
DISCONNECTED |
8.2 Server Command
{
"cmd": "display",
"lines": [
{"text": "HOGU RED", "y": 0},
{"text": "IMPACT!", "y": 30, "color": "green"}
],
"refresh": true
}
9. Telemetry: Battery & Health Monitoring
9.1 Battery Measurement (All Devices)
float readBatteryVoltage() {
int adc = analogRead(BATTERY_PIN);
float voltage = (adc / 4095.0) * 3.3 * 2.0; // 2:1 divider
return voltage;
}
int getBatteryLevel(float voltage) {
if (voltage >= 4.2) return 100;
if (voltage <= 3.3) return 0;
return (int)((voltage - 3.3) / 0.9 * 100);
}
9.2 Telemetry Frequency
- Every 60 seconds
- Or on significant change (e.g., battery drop >5%)
10. Feedback: Vibration, LED, Buzzer
10.1 Pin Assignments (Shared)
| Component | GPIO |
|---|---|
| Vibration Motor | 4 |
| Buzzer | 5 |
| LED (RGB) | 6 (R), 7 (G), 8 (B) |
| OLED (SDA) | 21 |
| OLED (SCL) | 22 |
| FSR (Hogu) | 34 |
| FSR (Head) | 35 |
| MPU6050 (SCL/SDA) | 21, 22 (shared with OLED) |
Use I2C multiplexer if needed.
10.2 Feedback Examples
Vibrate (200ms)
{"cmd": "vibrate", "duration": 200}
LED: Green Blink (3 times)
{"cmd": "led", "color": "#00FF00", "mode": "blink", "count": 3}
Buzzer: Short beep
{"cmd": "buzz", "tone": 1000, "duration": 150}
11. Command & Response Format
11.1 Outgoing (Device → Server)
{"type":"impact","device":"head_blue","force":720,"spinning":false,"time":1712345678903}
{"type":"telemetry","device":"HOGU_RED","battery_level":88,"rssi":-65,"timestamp":1712345679000}
11.2 Incoming (Server → Device)
{"cmd":"vibrate","duration":200}
{"cmd":"led","color":"#0000FF","mode":"solid"}
{"cmd":"display","lines":[{"text":"IMPACT!","y":30}]}
{"cmd":"ping"}
Device responds to
pingwith:
{"ack":"ping","time":1712345679100}
12. ESP32 Code Structure (Modular)
Use a modular design with shared components:
/src/
├── main.cpp
├── wifi_manager.cpp
├── tcp_client.cpp
├── oled_display.cpp
├── battery_monitor.cpp
├── sensors/
│ ├── fsr.cpp
│ └── mpu6050.cpp
├── feedback/
│ ├── vibration.cpp
│ ├── buzzer.cpp
│ └── led.cpp
└── device_config.h
Example: device_config.h
#define DEVICE_NAME "HOGU_RED"
#define DEVICE_TYPE "SENSOR"
#define OLED_ADDR 0x3C
#define BATTERY_PIN 35
#define VIBRO_PIN 4
#define BUZZER_PIN 5
#define LED_PIN 6
13. Android .NET Server Integration
Send Command to Any Device
void SendCommand(string mac, string commandJson)
{
TcpClient client = GetDeviceByMac(mac);
if (client?.Connected == true)
{
var stream = client.GetStream();
var writer = new StreamWriter(stream);
await writer.WriteLineAsync(commandJson);
await writer.FlushAsync();
}
}
Example: Confirm Impact
// After auto-scoring
SendCommand("30:85:A9:12:34:56", "{\"cmd\":\"vibrate\",\"duration\":200}");
SendCommand("30:85:A9:12:34:56", "{\"cmd\":\"led\",\"color\":\"#00FF00\",\"mode\":\"blink\",\"count\":2}");
Broadcast to All Sensors
foreach (var device in GetAllSensors())
{
SendCommand(device.Mac, "{\"cmd\":\"display\",\"lines\":[{\"text\":\"MATCH START\"}]}");
}
14. Best Practices
| Practice | Why |
|---|---|
| Send telemetry every 60 sec | Monitor battery and health |
| Debounce sensor inputs | Prevent false triggers |
| Use I2C for OLED & MPU6050 | Save pins |
Add ping command |
Check device liveness |
| Log all commands | Debugging and auditing |
| Low-power mode | Extend battery life |
| Clear OLED on boot | Avoid ghosting |
| Validate MAC before sending | Prevent errors |