Added IR Lib, samples and specification
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 12s

This commit is contained in:
2026-01-04 20:53:39 +01:00
parent 2cb0a33b8e
commit 667600c14e
19 changed files with 546 additions and 6 deletions

View File

@@ -107,13 +107,23 @@ sequenceDiagram
* **Status:** `GAME_STATE_RUNNING`.
* **Aktion:** Waffen sind entsperrt. Sensoren sind scharf.
* **Treffer-Logik (Dezentral):**
1. Waffe A schießt (sendet IR-Code mit `ShooterID` + `Damage`).
2. Weste B empfängt IR-Signal.
1. Waffe A schießt (sendet IR-Frame mit `Type=Hit`, `ShooterID`, `Damage`, `CRC8`).
2. Weste B empfängt IR-Signal über TSOP4838, validiert CRC.
3. Weste B berechnet Schaden (unter Berücksichtigung von Trefferzone-Multiplikator).
4. Weste B zieht Lebenspunkte ab.
5. **Feedback:** Weste B leuchtet/vibriert/spielt Sound ("Ugh!").
6. **Speicherung:** Weste B speichert den Treffer im internen Flash-Log (`Timestamp, ShooterID, Zone, Damage`).
7. *(Optional)* Weste B sendet UDP-Paket an Leader für Live-Scoreboard (Best Effort).
!!! info "Warum kein MilesTag2?"
MilesTag2 wurde als Basis erwogen, ist aber mit ~40 ms Frame-Zeit und starren 8-Bit-IDs zu langsam und unflexibel. Unser Custom-Protokoll bietet:
- **Kürzere Frames:** ~36 ms vs. ~40 ms (weniger anfällig für Zittern/Bewegung)
- **Flexible Type-Codes:** Hit/Heal/PowerUp/Admin in einem Format
- **CRC8-Prüfung:** >99.5% Fehlerrate-Erkennung bei Sonnenlicht
- **Variable Daten:** 13-Bit-Payload anpassbar pro Type
Details siehe [IR-Protokoll-Spezifikation](../specifications/ir_protocol.md).
* **Heilquellen:** Medic/Medipack-IR (breit gestreut, kurze Reichweite, negativer Damage) werden als Heilung interpretiert.
* **Zonen-Effekte:** Bases/Joiner senden `game/zone` (Link-Local, Hop=1); Weste prüft RSSI-Schwelle und addiert HP-Deltas (friend/foe) nach optionalem Warn-Countdown.

View File

@@ -39,7 +39,7 @@ Diese Roadmap führt vom nRF52840DK bis zum fertigen Produkt.
- [ ] Zephyr Setup: Installation des nRF Connect SDK (NCS) und VS Code.
- [ ] Custom Board Definition: Board-File anlegen, das die Pins des nRF52840DK auf die geplanten Funktionen mappt (PWM für IR, GPIO für Buttons).
- [ ] Thread Mesh: Minimalen OpenThread-Stack aufsetzen. Ein DK als Leader (FTD), einer als Child. UDP/CoAP-Ping bei Knopfdruck.
- [ ] IR-Engine: MilesTag-Encoder mit nrfx_pwm + PPI implementieren. Signal mit Oszilloskop/Logic Analyzer verifizieren. Sicherstellen, dass Funk die IR-Engine nicht stört.
- [ ] IR-Engine: Custom IR-Protokoll (pulse-distance, 38 kHz) mit nrfx_pwm + PPI implementieren. Signal mit Oszilloskop/Logic Analyzer verifizieren. Sicherstellen, dass Funk die IR-Engine nicht stört. **Hinweis:** MilesTag2 wurde verworfen zugunsten eines eigenen, kürzeren Protokolls mit CRC8 (siehe [Spezifikationen](specifications/ir_protocol.md)).
#### Phase 2: Der "Prototyp" (Integration)
**Ziel:** Einbindung von Audio und Solenoid.

View File

@@ -0,0 +1,201 @@
# IR-Kommunikationsprotokoll
## Übersicht
Das Infrarot-Kommunikationsprotokoll basiert auf Pulse-Distance-Codierung mit 38 kHz Träger und ist ähnlich Sony SIRC, aber optimiert für die Anforderungen des Lasertag-Systems. Das Protokoll bietet robuste Übertragung mit CRC-Fehlerprüfung und kurzen Frame-Zeiten (~36 ms).
## Physikalische Schicht
| Parameter | Wert | Anmerkung |
|-----------|------|----------|
| Trägerfrequenz | 38 kHz | Standard für TSOP48xx Empfänger |
| Tastgrad (Duty Cycle) | 50 % | Konfigurierbar (2575 %) |
| Modulation | PWM mit Pulse-Distance-Codierung | Hardware-basiert via nRF52 PWM-Peripheral |
| Empfänger | TSOP4838 (kompatibel) | Active-Low Ausgang, 38 kHz Bandpass |
## Timing-Spezifikation
| Symbol | Dauer | Toleranz | Beschreibung |
|--------|-------|----------|-------------|
| **Start Burst** | 2400 µs | ±200 µs | Frame-Synchronisations-Impuls |
| **Mark** | 600 µs | ±100 µs | Träger AN (konstant für alle Bits) |
| **Space 0** | 600 µs | ±100 µs | Träger AUS für logisch 0 |
| **Space 1** | 1200 µs | ±150 µs | Träger AUS für logisch 1 |
### Bit-Codierung
```
Bit 0: [Mark 600µs] + [Space 600µs] = 1.2 ms
Bit 1: [Mark 600µs] + [Space 1.2ms] = 1.8 ms
```
### Beispiel-Wellenform (3 Bits: `101`)
**Träger-Timing für Bits 1-0-1:**
| Segment | Dauer | State | Bit-Wert |
|---------|-------|-------|---------|
| Mark | 600 µs | AN | |
| Space 1 | 1200 µs | AUS | **1** (1.8 ms total) |
| Mark | 600 µs | AN | |
| Space 0| 600 µs | AUS | **0** (1.2 ms total) |
| Mark | 600 µs | AN | |
| Space 1| 1200 µs | AUS | **1** (1.8 ms total) |
```mermaid
block-beta
columns 8
mark1["Mark<br>600 µs"] space1["Space 1<br>1200 µs"]:2 mark2["Mark<br>600 µs"] space2["Space 0<br>600 µs"] mark3["Mark<br>600 µs"] space3["Space 1<br>1200 µs"]:2
bit1["<b>1</b>"]:3 bit2["<b>0</b>"]:2 bit3["<b>1</b>"]:3
style space1 fill:none
style space2 fill:none
style space3 fill:none
```
## Frame-Format
Alle Frames bestehen aus 24 Bits, übertragen MSB-first:
| Feld | Start Burst | Type | Data | CRC8 |
|------|-------------|------|------|------|
| **Dauer** | 2400 µs | 3 Bits | 13 Bits | 8 Bits |
| **Funktion** | Synchronisation | Frame-Typ | Payload | Fehlerprüfung |
| **Summe** | | | | **24 Bits** |
```mermaid
packet-beta
title Frame
+3: "Typ"
+13: "Payload"
+8: "Fehlerprüfung"
```
**Gesamte Frame-Zeit:** ~36 ms (Start + 24 × 1.5 ms durchschnittliche Bit-Zeit)
### Type-Feld (3 Bits)
| Wert | Typ | Beschreibung |
|------|-----|-------------|
| `000` | Hit | Standard-Schuss |
| `001` | Heal | Medic-Heilung oder Health Pack |
| `010` | PowerUp | Station Power-Up Grant |
| `011` | Admin | System-Steuerbefehle |
| `100``111` | Reserviert | Zukünftige Nutzung |
### Data-Feld (13 Bits) Type-abhängig
#### Hit-Frame (`000`)
| Bit-Range | Feld | Wertbereich | Beschreibung |
|-----------|------|-------------|-------------|
| 07 | Shooter ID | 0255 | ID des Schützen (256 mögliche Spieler) |
| 812 | Damage | 031 | Schadenpunkte (0 = kein Schaden, 31 = Maximum) |
#### Heal-Frame (`001`)
| Bit-Range | Feld | Wertbereich | Beschreibung |
|-----------|------|-------------|-------------|
| 07 | Healer ID | 0255 | ID des Heilers (Medic oder Station) |
| 812 | Amount | 031 | Heilpunkte wiederhergestellt |
#### PowerUp-Frame (`010`)
| Bit-Range | Feld | Wertbereich | Beschreibung |
|-----------|------|-------------|-------------|
| 07 | Station ID | 0255 | Stations-ID, die das Power-Up gewährt |
| 812 | PowerUp | 031 | Power-Up-Typ-Identifier |
#### Admin-Frame (`011`)
| Bit-Range | Feld | Wertbereich | Beschreibung |
|-----------|------|-------------|-------------|
| 012 | Command Data | 08191 | Implementierungsdefinierte Steuerbefehle |
### CRC-Feld (8 Bits)
- **Algorithmus:** CRC-8-CCITT
- **Polynom:** 0x07 (x⁸ + x² + x + 1)
- **Initialwert:** 0x00
- **Eingabe:** Type (3 Bits) + Data (13 Bits) = 16 Bits
- **Zweck:** Fehlererkennung bei Bitfehlern durch Umgebungslicht oder Interferenzen
**Erwartete Fehlererkennungsrate:** >99.5 % für Einfach- oder Doppelbitfehler
## Beispiel-Frame
**Hit von Spieler 42 mit 10 Schaden:**
```
Type: 000 (Hit)
Data: 00101010 01010 (ShooterID=42, Damage=10)
CRC8: [berechnet aus obigen Daten]
Kompletter Frame (24 Bits):
000 00101010 01010 CCCCCCCC
│ │ │ └─ CRC8
│ │ └─ Damage (10)
│ └─ Shooter ID (42)
└─ Type (Hit)
```
**Übertragungsabfolge:**
1. Start Burst: 2400 µs Träger AN
2. Bit 0 (Type): 600 µs Mark + 600 µs Space
3. Bit 1 (Type): 600 µs Mark + 600 µs Space
4. Bit 2 (Type): 600 µs Mark + 600 µs Space
5. ... (21 weitere Bits)
6. Ende: Träger AUS
## Empfänger-Implementierung
### Hardware-Anforderungen
- TSOP4838 verbunden mit GPIO mit Interrupt-Fähigkeit
- Steigende/fallende Flanken-Erkennung
- Timer zur Messung der Space-Dauern
### Software-State-Machine
1. **IDLE:** Auf Start Burst warten (20002800 µs)
2. **SYNC:** Start Burst erkannt, Vorbereitung zur Bit-Empfang
3. **DATA:** Space nach jedem Mark messen, 24 Bits dekodieren
4. **VALIDATE:** CRC prüfen, Frame bei Gültigkeit verarbeiten
### Timing-Toleranzen
- Breite Toleranzbereiche (±1733 %) kompensieren Interrupt-Jitter und Träger-Drift
- Fehlgeschlagener CRC zeigt beschädigten Frame an → stille Verwerfung
- Empfänger resynchronisiert automatisch beim nächsten Start Burst
## Konfigurierbare Parameter
Die Protokoll-Timing kann via Kconfig für verschiedene Umgebungen angepasst werden:
- `CONFIG_IR_SEND_CARRIER_HZ`: Trägerfrequenz (3045 kHz)
- `CONFIG_IR_SEND_DUTY_CYCLE_PERCENT`: PWM Tastgrad (2575 %)
- `CONFIG_IR_SEND_MARK_US`: Mark-Dauer (3001000 µs)
- `CONFIG_IR_SEND_SPACE0_US`: Space für Bit 0 (3001000 µs)
- `CONFIG_IR_SEND_SPACE1_US`: Space für Bit 1 (8002000 µs)
- `CONFIG_IR_SEND_START_BURST_US`: Start Burst (15004000 µs)
Die Standardwerte folgen Sony SIRC Timing-Konventionen für bewährte Zuverlässigkeit.
## Leistungscharakteristiken
| Metrik | Wert |
|--------|------|
| Frame-Zeit | ~36 ms |
| Datenrate | ~670 bit/s |
| Max. Spieler-IDs | 256 |
| Reichweite (Außen) | ~510 m (abhängig von Sender-Leistung und Umgebungslicht) |
| Fehler-Erkennung | >99.5 % via CRC-8 |
| Störfestigkeit | Hoch (Hardware-Bandpass 38 kHz) |
---
## Bluetooth LE Protokoll
*Zu dokumentieren: BLE-Charakteristiken für Spielstatus-Synchronisierung, Team-Zuordnung, etc.*