From 06af540be371477b9776e33949fa6a00c525dba9 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Sat, 3 Jan 2026 11:20:42 +0100 Subject: [PATCH] Konzepte angepasst und erweitert --- .gitignore | 2 + doc/docs/index.md | 14 +- doc/docs/konzept/hardware.md | 172 ++++++++++++++++++ doc/docs/konzept/software.md | 322 ++++++++++++++++++++++++++++++++++ doc/docs/konzept_hardware.md | 118 ------------- doc/hardware.md | 56 ++++++ doc/mkdocs.yml | 3 +- doc/software.md | 194 ++++++++++++++++++++ firmware/apps/weapon/main.c | 110 ++++++++++++ firmware/apps/weapon/prj.conf | 21 ++- 10 files changed, 891 insertions(+), 121 deletions(-) create mode 100644 doc/docs/konzept/hardware.md create mode 100644 doc/docs/konzept/software.md delete mode 100644 doc/docs/konzept_hardware.md create mode 100644 doc/hardware.md create mode 100644 doc/software.md create mode 100644 firmware/apps/weapon/main.c diff --git a/.gitignore b/.gitignore index 6638c01..a933ad5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ **/.vscode **/__pycache__/ *.py[cod] +doc/site + diff --git a/doc/docs/index.md b/doc/docs/index.md index ea54c4d..5f39f3b 100644 --- a/doc/docs/index.md +++ b/doc/docs/index.md @@ -1,3 +1,15 @@ # Eriks Lasertag -Das hier beschreibt das ganze Lasertag-Gedöns. +Kurzer Überblick über das DIY-Lasertag-System auf Basis von nRF52840, Thread und BLE. + +**Was dich hier erwartet** + +- Architektur & Spielablauf: siehe Konzept Software. +- Hardware-Ideen: Waffe, Weste, Leader, Stromversorgung. +- Roadmap & To-Dos: grobe Phasen und Module. + +**Schnelleinstieg** + +- Konzept Software: Rolle Leader/Weste/Waffe, Game Loop, CoAP-API. +- Konzept Hardware: Aufbau der Einheiten, LED-Treiber, Akku-Setup. +- Planung: Zephyr-Workspace-Struktur und Roadmap. diff --git a/doc/docs/konzept/hardware.md b/doc/docs/konzept/hardware.md new file mode 100644 index 0000000..f0404ff --- /dev/null +++ b/doc/docs/konzept/hardware.md @@ -0,0 +1,172 @@ +# Hardware-Konzept + +Dieses Dokument beschreibt die physischen Komponenten des Lasertag-Systems. Alle Knoten basieren auf dem Nordic nRF52840 SoC. + +**Ziele:** robuste Outdoor-Tauglichkeit, klare Rollen-Trennung (Waffe/Weste/Leader), einfache Wartung (Steckverbinder, modulare Boards) und reproduzierbare Reichweite über saubere Stromversorgung. + +## 1. Geräteübersicht + +### 1.1 Waffe (Weapon Unit) + +Die Waffe ist das primäre Interaktionsgerät. Sie muss robust und reaktionsschnell sein. + +* **Controller:** nRF52840 (Dongle oder Modul). +* **IR-Sender:** High-Power IR-LED (940nm oder 850nm) mit Optik/Linse und Treiberstufe (Reichweite > 50m). +* **Feedback:** Muzzle Flash (helle LED), Vibrationsmotor, Audio (Schussgeräusche, "Leer"-Klicken). +* **Eingabe:** Abzug (Trigger), Nachladen (Taster), optionaler Schalter für Feuermodus. +* **Stromversorgung:** 2S LiPo (7.4V) mit Step-Down auf 3.3V. + +### 1.2 Weste (Player Hub) + +Die Weste ist die zentrale Recheneinheit des Spielers und trägt die Sensorik. + +* **Controller:** nRF52840 DK oder Custom Board. +* **Sensorik (IR-Empfänger):** Verteilte Sensoren für 360° Abdeckung (Kopf, Brust/Rücken, Schultern). +* **Beleuchtung:** Adressierbare RGB-LEDs (WS2812B) an den Sensor-Positionen für Teamfarbe/Treffer. +* **Audio:** Leistungsstarker Lautsprecher für Sprachausgabe. +* **Verbindung:** Zentrale Box am Rücken mit Steckverbindern zu den Sensorgruppen. + +### 1.3 Leader Box (Game Controller) + +Die Leader Box dient zur Spielsteuerung und als Infrastruktur-Knoten. + +* **Controller:** nRF52840. +* **Modi (Hardware-Schalter):** 2 DIP-Schalter zur Wahl von Leader / Repeater / Base. +* **Ausstattung:** IR-Empfänger, RGB-LEDs, Bluetooth-Gateway zur Smartphone-App. +* **Stromversorgung:** Großer Akku für lange Laufzeit. + +## 2. Energie & Verkabelung + +* **Akkus:** 2S LiPo (7.4V) als Standard; 1S nur für Tests/Low-Power-Aufbau. +* **Spannungswandler:** Abwärtswandler auf 3.3V für Logik, separater Treiberpfad für IR-LEDs (hoher Pulsstrom, niedriger Duty-Cycle). +* **Verkabelung Weste:** Sternförmige Abgänge zu Sensorgürteln (Kopf, Brust/Rücken, Schultern) mit verriegelnden Steckern; Datensignal (LED) + Versorgung gebündelt. +* **Absicherung:** Polyfuse pro Ast empfohlen, Verpolschutz an jedem Modulanschluss. + +## 3. Stückliste (Übersicht) + +Diese Tabelle gibt einen Überblick über die groben Komponenten pro Einheit. Detaillierte Part Numbers und Bezugsquellen folgen in separaten Docs. + +| Komponente | Waffe | Weste | Leader | Menge | Anmerkung | +| :--- | :--- | :--- | :--- | :--- | :--- | +| nRF52840 (SoC/Modul) | ✓ | ✓ | ✓ | 1/Gerät | Zephyr SDK Support | +| IR-LED (High-Power) | ✓ | | | | 940nm, > 50m Reichweite | +| IR-Empfänger (38kHz) | | ✓ | ✓ | 5–10 | Verteilt auf Kopf/Torso/Schulter | +| RGB-LED (WS2812B) | | ✓ | ✓ | 1–3 | Teamfarbe + Status | +| Vibrationsmotor | ✓ | | | | Taktiles Feedback Schuss | +| Lautsprecher | ✓ | ✓ | | | Schussgeräusche + Sprachausgabe | +| 2S LiPo Akku | ✓ | ✓ | ✓ | 1 | 7.4V, ggf. unterschiedliche Kapazität | +| Lade-IC (IP2326) | ✓ | ✓ | ✓ | 1 | 2S Balancing | +| Zellenschutz (FS8205A) | ✓ | ✓ | ✓ | 1 | Verpolschutz + OV/UV | +| Spannungsteiler-ADC | ✓ | ✓ | ✓ | 1 | Fuel Gauge (R1=100k, R2=47k) | +| Taster (Trigger/Reload) | ✓ | | | | Auch optional Dip-Switch für Leader | +| USB-C / Pogo-Pad | ✓ | ✓ | ✓ | 1 | Laden + Debug-Konsole | +| Steckverbinder (JST-XH) | ✓ | ✓ | | | Modular aufgebaut | + +## 4. Schaltungskomponenten + +### 4.1 LED-Treiber + +#### Grundkonzept + +Der LED-Treiber realisiert eine präzise Konstantstromquelle als Hybridschaltung aus PNP- und NPN-Transistoren. Diese Architektur ermöglicht eine stabile und effiziente Ansteuerung von Infrarot-Leuchtdioden mit definierten Stromwerten. + +![LED DRIVER](../img/concept_hardware_led_driver.svg) + +#### Stromeinstellung + +Der Zielstrom wird über den Messwiderstand $R_{set}$ eingestellt. Die Berechnung folgt der Formel: + +$$R_{set} = \frac{0,65V}{I_{LED}}$$ + +Die folgenden Tabelle zeigt typische Stromwerte, die erforderlichen Widerstände und die entsprechenden Anwendungsfälle: + +| Stromstärke ($I_{LED}$) | Widerstand ($R_{set}$) | Ausgangsleistung ($P_{min}$) | Einsatzbereich | +| :--- | :--- | :--- | :--- | +| 0,5 A | 1,30 $\Omega$ | 0,5 W | Standard / Nahkampf | +| 1,0 A | 0,65 $\Omega$ | 1,0 W | Hohe Reichweite (SFH 4550) | +| 2,0 A | 0,33 $\Omega$ | 2,0 W | Extrem hohe Leistung (Pulsbetrieb) | +| 3,0 A | 0,22 $\Omega$ | 3,0 W | Scharfschützen-Modus (Oslon Black) | + +#### Thermische Betrachtung + +Im Lasertag-Betrieb werden die Infrarot-Signale hochfrequent moduliert (beispielsweise mit 38 kHz). Dies führt zu einem signifikant geringeren mittleren Wärmeeintrag in den Messwiderstand als eine kontinuierliche Strombelastung suggeriert: + +$$P_{avg} = (R_{set} \cdot I_{LED}^2) \cdot \text{Duty Cycle}$$ + +!!! info "Bedeutung der Widerstandsspezifikation" + Obwohl die Duty-Cycle-Modulation die durchschnittliche Verlustleistung reduziert, müssen Widerstände für $R_{set}$ für die auftretenden Stromspitzen ausgelegt sein. Wir empfehlen impulsfeste Typen (Metallschicht- oder Drahtwiderständen), um die Stromspitzen bis zu 3 A ohne Materialermüdung zu verkraften. + +#### Spannungsversorgung und Headroom-Anforderungen + +Die Konstantstromquelle benötigt eine Mindestverspannung zwischen Versorgung und Ausgang, um präzise die Sollstromstärke zu halten. Diese sogenannte Headroom-Spannung errechnet sich aus: + +$$V_{CC} > V_{f(\text{LED})} + 0,65V + 1,0V_{\text{Headroom}}$$ + +**Kritischer Aspekt bei Lithium-Ionen-Akkus:** Die Akkuspannung sinkt während der Entladung kontinuierlich. Unterschreitet $V_{CC}$ den erforderlichen Schwellwert, bricht die Regelung zusammen und der LED-Strom kann die Sollvorgabe nicht mehr erreichen. Dies führt zu einer drastischen Reduktion der Reichweite des Senders. + +Die Minimalspannung für stabilen Betrieb wird bestimmt durch: + +$$V_{CC,\text{min}} = V_{f(\text{LED})} + V_{R_{set}} + V_{\text{Headroom}}$$ + +Die folgende Tabelle zeigt die erforderlichen Minimalspannungen für verschiedene Stromvorgaben und die Eignung unterschiedlicher Akkusysteme: + +| Stromstärke ($I_{LED}$) | Typ. LED-Spannung ($V_{f}$) | Erforderliche Spannung ($V_{CC,\text{min}}$) | Akku-Empfehlung | +| :--- | :--- | :--- | :--- | +| 0,5 A | ~2,0 V | 3,65 V | 1S (nur bei voller Ladung) | +| 1,0 A | ~2,4 V | 4,05 V | 2S empfohlen | +| 2,0 A | ~2,8 V | 4,45 V | 2S erforderlich | +| 3,0 A | ~3,2 V | 4,85 V | 2S erforderlich | + +!!! warning "1S-System: Einschränkungen unter Last" + Ein einzelner 1S Li-Po Akku sinkt unter hohen Stromlasten schnell auf 3,4 V bis 3,6 V ab. Für konstante Reichweite bei Strömen ab 1 A ist ein 2S-System daher technisch überlegen. + +#### 2S-Akkusystem: Komplexität und Lösungsansätze + +Ein 2S-Akkusystem bietet zwar Spannungsstabilität, erfordert jedoch anspruchsvollere Schutz- und Überwachungsfunktionen: + +- **Laden:** Moderne 2S-Ladechips mit integriertem Balancing (beispielsweise der IP2326) ermöglichen vereinfachte Ladevorgänge. +- **Zellenschutz:** Ein Zellenschutz-IC wie der HY2120-CB in Kombination mit einem Dual-Channel MOSFET (beispielsweise FS8205A) verhindert Über- und Unterspannungszustände. +- **Fuel Gauge:** Spezielle Fuel-Gauge-ICs für 2S-Systeme sind selten oder komplex. Als praktische Alternative wird eine Spannungsteiler-ADC-Messung zur Ladezustandsabschätzung eingesetzt. Der Spannungsteiler muss durch ein Schaltgattersystem steuerbar sein. + +### 4.2 Audio-Driver +Um Audio (z. B. Schussgeräusche, Sprachansagen) von einem externen Flash abzuspielen, ohne die CPU zu belasten, müssen wir auf Hardware-DMA-Transfer setzen. + +Die beste Lösung für ein kompaktes, batteriebetriebenes System wie eine Lasertag-Waffe ist ein I2S Class-D Verstärker. Dieser kombiniert DAC und Verstärker in einem Chip und wird digital angesteuert. + +Der "Industriestandard" für Mikrocontroller ist da der MAX98357A: + +* **Schnittstelle**: I2S (Digital) +* **Leistung**: 3.2W an 4Ω (sollte mehr als genug laut sein) +* **Vortiele**: + * Kein externer DAC nötig + * Direkter Anschluss an den Lautsprecher + * Extrem Energieeffizient (schont die Akkus) + * Filterlose Class-D Architektur (wenige Bauteile) +* **CPU-Last**: Minimal, da der nRF52840 die Daten per EasyDMA schickt (zur Anpassung der Lautstärke wird etwas Rechenleistung benötigt) + +### 4.3 Akku-Überwachung (Fuel Gauge) + +#### Spannungsmessung bei 2S-Akkus + +Für 2S-Akkusysteme mit Spannungen bis 8,4 V wird die Akkuspannung über einen Spannungsteiler auf den ADC-Eingangspegel reduziert. Dieser Messwert dient zur Ladezustandsabschätzung und Fehlerdiagnose. + +#### Schaltungskomponenten + +| Komponente | Wert | Funktion | +| :--- | :--- | :--- | +| $R_1$ | 100 k$\Omega$ | Spannungsteiler – oberer Zweig | +| $R_2$ | 47 k$\Omega$ | Spannungsteiler – unterer Zweig | +| $C_1$ | 100 nF | Glättungskondensator am ADC-Eingang | + +#### Softwarelogik + +Die Ladezustandsbestimmung erfolgt in drei Schritten: + +1. **ADC-Konvertierung:** Der Rohwert des ADC-Eingangs wird eingelesen. +2. **Spannungsrückrechnung:** Die Realspannung wird aus dem ADC-Wert berechnet: $V_{\text{bat}} = V_{\text{adc}} \cdot \frac{R_1 + R_2}{R_2}$ +3. **Ladezustand-Mapping:** Die Batteriespannung wird auf einen prozentualen Ladezustand abgebildet: + * **6,0 V** → 0 % (Entladungsschutz aktiv) + * **8,4 V** → 100 % (vollständig geladen) + * Für höhere Genauigkeit können mehrere Messpunkte verwendet und linear interpoliert werden. + +*Stand: 03.04.2025* \ No newline at end of file diff --git a/doc/docs/konzept/software.md b/doc/docs/konzept/software.md new file mode 100644 index 0000000..2a24445 --- /dev/null +++ b/doc/docs/konzept/software.md @@ -0,0 +1,322 @@ +# Software-Konzept & Spielablauf + +Dieses Dokument beschreibt die Software-Architektur, die Rollenverteilung und die Kommunikationsabläufe des Lasertag-Systems. + +## Überblick + +* Architektur: Leader als BLE/Thread-Brücke, Westen als Spiel-Authority für Health/Regeln, Waffen als Sensor/Aktor. +* Funk: BLE für Provisionierung/App, Thread (CoAP/UDP) für Spielverkehr, IR für Treffer-Übertragung. +* Prinzip: Dezentraler Trefferentscheid (auf der Weste) mit optionalem Live-Ticker zum Leader; Leader hält Spielstatus und sammelt Logs. + +## 1. System-Rollen & Hardware-Typen + +Das System basiert auf nRF52840-Chips, die über OpenThread (802.15.4) kommunizieren. + +### A. Leader Box (Game Controller) +* **Funktion:** Zentrale Spielsteuerung, Zeitgeber, Gateway zur Smartphone-App. +* **Modi (wählbar via DIP-Schalter):** + * `00` **Leader:** Spielleiter, BLE-Gateway, sammelt Punkte. + * `01` **Repeater:** Router im Mesh zur Reichweitenverlängerung (z.B. am Baum). + * `11` **Base:** Interaktives Ziel (z.B. für "Domination"-Modus). +* **Hardware:** IR-Empfänger, RGB-LEDs, BLE aktiv. + +### B. Weste (Player Hub) +* **Funktion:** Zentrale Einheit des Spielers. Verwaltet Lebenspunkte, empfängt Treffer, steuert Audio. +* **Sensoren:** Kopf (3x: Stirn, Links, Rechts), Brust/Rücken, Seiten (Schultern/Arme). +* **Kommunikation:** Hält die Verbindung zur Waffe (Pairing) und zum Leader. + +### C. Waffe +* **Funktion:** Aussenden der IR-Signale, haptisches Feedback, Muzzle-Flash. +* **Typen:** Pistole, Sniper, Shotgun (unterschiedliche IR-Leistung/Fokussierung). +* **Logik:** Sendet "Schuss"-Events, empfängt "Sperren"-Befehle von der Weste (wenn tot). + +--- + +## 2. Provisionierung & Setup (Lobby-Phase) + +Bevor das Spiel startet, müssen Geräte dem Netzwerk beitreten und Spielern zugeordnet werden. + +### Schritt 1: Netzwerk-Beitritt (Provisioning) +* **Szenario:** Neue Hardware wird zum ersten Mal verwendet. +* **Ablauf:** + 1. Spielleiter verbindet App via BLE mit **Leader Box**. + 2. Leader Box öffnet das Thread-Netzwerk (Commissioning). + 3. Neue Geräte (Waffe/Weste) werden in den Pairing-Modus versetzt (z.B. Tastenkombination). + 4. Geräte erhalten Netzwerk-Credentials und treten dem Mesh bei. + +### Schritt 2: Spieler-Konfiguration (Assignment) +* **Ziel:** Zuordnung von Hardware zu einer logischen `PlayerID` und einem `Team`. +* **Identifikation:** Jedes nRF52-Board hat eine eindeutige **EUI-64** (MAC). +* **Ablauf:** + 1. App scannt **QR-Code** oder **NFC-Tag** an der Weste/Waffe (Payload: EUI-64 Adresse). + 2. App sendet Konfiguration an Leader Box: `EUI-64 -> {PlayerID, Team, Name}`. + 3. Leader Box löst EUI-64 in aktuelle IPv6-Adresse auf (Neighbor Table / Discovery). + 4. Leader sendet Konfigurations-Paket (CoAP Unicast) an das Gerät: + * **Weste:** Erhält PlayerID, TeamID, MaxHealth, evtl. Rolle. + * **Waffe:** Erhält Damage-Wert, Nachladezeit, Magazingröße, Waffentyp. + 5. Geräte speichern ID/Team im RAM (optional NVS für Persistenz bei Neustart). + +### Provisioning – Sequenzdiagramm + +```mermaid +sequenceDiagram + actor User as Spielleiter + participant App + participant Leader + participant Weste + participant Waffe + + User->>App: Verbindung via BLE + App->>Leader: Thread-Credentials (BLE) + Leader->>Leader: Öffne Mesh für Provisioning + + User->>Weste: Pairing-Modus aktiviert + User->>Waffe: Pairing-Modus aktiviert + + Weste->>Leader: Beitritt ins Thread-Netz + Waffe->>Leader: Beitritt ins Thread-Netz + + User->>App: QR-Code Weste scannen + App->>Leader: PlayerID 1, Team=Rot, Name="Alice" + Leader->>Weste: Konfig (CoAP PUT /game/conf) + Weste->>Weste: Speichere PlayerID=1, Team=Rot + + User->>App: QR-Code Waffe scannen + App->>Leader: PlayerID 1, Waffentyp=Pistol + Leader->>Waffe: Konfig (CoAP PUT /game/wconf) + Waffe->>Waffe: Speichere Damage=10, ReloadTime=500ms + + App->>Leader: "Spieler bereit?" + Leader->>App: Ping alle Knoten → OK +``` + +--- + +## 3. Spielablauf (Game Loop) + +### Phase A: Vorbereitung +* **Leader:** Sendet Multicast `GAME_STATE_LOBBY`. +* **Geräte:** Spielen Idle-Animation ab, warten auf Start. +* **Check:** Leader kann "Ping" an alle senden, um Anwesenheit zu prüfen. + +### Phase B: Countdown +* **Leader:** Sendet Multicast `GAME_START_COUNTDOWN` (Payload: 10 sek). +* **Westen:** Zählen laut herunter: "10, 9, 8...". + +### Phase C: Spiel läuft (Running) +* **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. + 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). + +### Phase D: Spieler eliminiert +* **Bedingung:** Lebenspunkte <= 0. +* **Weste B:** + * Spielt "Dead"-Sound. + * Leuchtet dauerhaft in Teamfarbe (oder aus). + * Sendet CoAP Unicast an **eigene Waffe**: `CMD_DISABLE`. +* **Respawn (falls aktiv):** + * Nach Zeitablauf (z.B. 30s) sendet Weste an Waffe: `CMD_ENABLE`. + * Lebenspunkte werden zurückgesetzt. + +### Phase E: Spielende & Auswertung +* **Leader:** Sendet Multicast `GAME_STATE_FINISHED`. +* **Ablauf:** + 1. Alle Spieler kommen zusammen. + 2. Spielleiter drückt in App "Daten abrufen". + 3. Leader Box fragt nacheinander (Unicast) alle bekannten Westen ab: `GET /game/log`. + 4. Westen übertragen ihre Treffer-Historie. + 5. App berechnet Highscores, MVP, Trefferquoten. + +### Game Loop – Zustandsautomat (Weste) + +```mermaid +stateDiagram-v2 + [*] --> Idle + + Idle --> Lobby: GAME_STATE_LOBBY empfangen + Lobby --> Countdown: GAME_START_COUNTDOWN empfangen + Countdown --> Running: Countdown = 0 + + Running --> Running: IR-Hit empfangen → Damage abzug, Log + Running --> Dead: Health <= 0 + + Dead --> Dead: Waffe CMD_DISABLE senden + Dead --> Running: Respawn aktiviert (CMD_ENABLE) + + Running --> Finished: GAME_STATE_FINISHED + Dead --> Finished: GAME_STATE_FINISHED + + Finished --> [*] + + note right of Running + - Health-Tracking + - Treffer-Log + - LED/Audio-Feedback + end note + + note right of Dead + - Waffe gesperrt + - LED dauerhaft an + - Optional Respawn-Timer + end note +``` + +--- + +## 4. Spielmodi + +Die Logik für die Modi wird primär auf den Westen implementiert (Regelwerk), gesteuert durch Flags vom Leader. + +### Team Deathmatch +* Klassisch Rot gegen Blau. +* Friendly Fire konfigurierbar (an/aus). +* Siegbedingung: Meiste Kills oder wenigste Tode nach Zeitablauf. + +### Last Man Standing (Free-for-all) +* Jeder gegen Jeden. +* Keine Teams (oder jeder hat eigene Team-ID). +* Kein Respawn. + +### Zombie (Infected) +* **Start:** 1 Spieler ist "Zombie" (Team Grün), Rest "Mensch" (Team Rot). +* **Regel:** + * Zombie hat unendlich Leben (oder sehr viel). + * Mensch hat 1 Leben. + * Wird Mensch getroffen -> Wechselt Team zu Zombie (Weste leuchtet grün, Waffe sendet ab jetzt Zombie-ID). + * Wird Zombie getroffen -> "Stunned" (Waffe 5s gesperrt). +* **Ziel:** Überleben bis Zeitablauf. + +### Base Domination +* **Hardware:** Leader-Boxen im Modus `11` (Base) verteilt im Gelände. +* **Ablauf:** + * Spieler schießt auf Base-Box. + * Base-Box wechselt Farbe zu Teamfarbe des Schützen. + * Base-Box zählt Zeit für das haltende Team. + * Am Ende fragt Leader alle Base-Boxen ab: "Wie lange warst du Rot? Wie lange Blau?". + +--- + +## 5. Technische Spezifikation (API & Datenstrukturen) + +Die Kommunikation erfolgt über CoAP (UDP). Alle Payloads sind binär (`__packed` C-Structs, Little Endian für nRF52, Network Byte Order für Interop optional). + +### 5.1 CoAP Endpunkte + +| Ressource | Methode | Typ | Beschreibung | Payload | +| :--- | :--- | :--- | :--- | :--- | +| `game/state` | PUT | Multicast | Globaler Spielstatus (Start/Stop/Zeit) | `struct game_state_packet` | +| `game/conf` | PUT | Unicast | Konfiguration für einen Spieler | `struct player_config_packet` | +| `game/wconf` | PUT | Unicast | Konfiguration für eine Waffe | `struct weapon_config_packet` | +| `game/hit` | POST | Unicast | Treffer-Meldung (Live-Ticker) | `struct hit_report_packet` | +| `game/log` | GET | Unicast | Abruf der gespeicherten Trefferdaten | `struct flash_log_entry[]` | + +### 5.2 Datenstrukturen + +#### Spielstatus (Multicast) +```c +struct game_state_packet { + uint8_t state; // 0=Idle, 1=Lobby, 2=Running, 3=Paused, 4=Finished + uint8_t game_mode; // 0=TeamDeathmatch, 1=Zombie, 2=Base + uint16_t game_id; // Rolling Counter zur Deduplizierung + uint16_t remaining_sec; // Restzeit in Sekunden + uint8_t flags; // Bitmaske (z.B. FriendlyFire) +} __packed; +``` + +#### Spieler-Konfiguration (Provisioning) +```c +struct player_config_packet { + uint16_t player_id; // Logische ID (1-65535) + uint8_t team_id; // 0=Rot, 1=Blau, 2=Grün (Zombie), ... + uint8_t role; // 0=Soldier, 1=Medic, 2=Sniper + uint8_t damage_out; // Basis-Schaden der Waffe + uint8_t health_max; // Maximale Lebenspunkte + char name[16]; // Anzeigename (null-terminated) +} __packed; +``` + +#### Waffen-Konfiguration +```c +struct weapon_config_packet { + uint8_t base_damage; // Schaden pro Schuss + uint16_t reload_time_ms;// Zeit für Nachladen + uint8_t magazine_size; // Schuss pro Magazin +} __packed; +``` + +#### Treffer-Bericht (Live & Log) +```c +struct hit_report_packet { + uint32_t timestamp; // ms seit Spielstart + uint16_t shooter_id; // ID des Schützen (aus IR) + uint16_t victim_id; // Eigene ID + uint8_t damage; // Erlittener Schaden + uint8_t hit_location; // 0=Unbekannt, 1=Kopf, 2=Brust, 3=Rücken +} __packed; +``` + +--- + +## 6. IR-Protokoll (Physical Layer) + +Das IR-Signal nutzt eine 38kHz Trägerfrequenz (NEC-ähnlich). +Payload (32-bit): +* `8 bit` Protokoll-ID (Magic Byte zur Unterscheidung von Fernbedienungen) +* `16 bit` Shooter ID +* `8 bit` Info (4 bit Team, 4 bit Damage Class) + +## 8. Weste – Zustandsautomat (detailliert) + +### Übergangstabelle + +| Von | Nach | Auslöser | Aktion | Bedingung | +| :--- | :--- | :--- | :--- | :--- | +| Idle | Lobby | CoAP `GAME_STATE_LOBBY` | LED idle-Animation, warten auf Start | Multicast vom Leader | +| Lobby | Countdown | CoAP `GAME_START_COUNTDOWN` | Audio-Countdown 10→1 sec, Countdown-Timer init | Payload: 10 sek | +| Countdown | Running | Countdown = 0 | Health reset, Treffer-Sensor aktivieren, Waffe unlock | Timer lokal abgelaufen | +| Running | Dead | Health <= 0 | LED rot/aus, Dead-Sound, CoAP CMD_DISABLE an Waffe | Nach IR-Hit-Verarbeitung | +| Dead | Running | Respawn-Timer = 0 | Health reset, CoAP CMD_ENABLE an Waffe, Sensor on | Optional; Config-abhängig | +| Running | Finished | CoAP `GAME_STATE_FINISHED` | Alle Daten sichern, Logs speichern, LED Idle | Multicast vom Leader | +| Dead | Finished | CoAP `GAME_STATE_FINISHED` | Logs speichern (optional), LED Idle | Multicast vom Leader | + +### Treffer-Verarbeitung im Running-State (Flowchart) + +```mermaid +flowchart TD + A["IR-Signal empfangen"] --> B{"ShooterID prüfen"} + B -->|Friendly Fire off + eigenes Team| C["Signal verwerfen"] + B -->|Valid| D["Hit Location extrahieren"] + D --> E["Zone-Multiplikator anwenden"] + E --> F["Effektiven Schaden berechnen"] + F --> G["Health -= Damage"] + G --> H{"Health > 0?"} + H -->|Ja| I["LED blinken + Sound"] + I --> J["Hit ins Flash-Log schreiben"] + J --> K["Optional: CoAP Hit-Report an Leader"] + H -->|Nein| L["Health = 0"] + L --> M["LED rot, Dead-Sound"] + M --> N["CoAP CMD_DISABLE an Waffe"] + N --> O["Zustand → Dead"] +``` + +### Übergangsbeschreibungen + +- **Idle → Lobby:** App oder Spielleiter triggert über BLE. Leader sendet `GAME_STATE_LOBBY` Multicast. Weste wechselt in Warte-Modus. +- **Lobby → Countdown:** Leader sendet `GAME_START_COUNTDOWN` mit Sekunden-Payload (z.B. 10). Weste zählt laut herunter. +- **Countdown → Running:** Timer lokal = 0 → Weste aktiviert Sensoren, Health voll, Waffe freigegeben. +- **Running → Dead:** Health <= 0 nach Treffer-Verarbeitung → Waffe gesperrt, LED rot/aus, Respawn-Timer optional starten. +- **Dead → Running:** Optional nur wenn Respawn aktiv. Leader schickt evtl. Kommando oder Timer läuft ab. +- **{Running|Dead} → Finished:** Leader sendet `GAME_STATE_FINISHED` → Weste speichert finale Logs, bereit für Auswertung. + +## 9. Offene Punkte & Annahmen + +* Sicherheitsmodell: Keine Auth auf IR, minimale Auth/ACL auf BLE/Thread? (noch zu klären). +* Anti-Cheat: Debounce IR, Rate-Limit pro Waffe, Rolling Codes möglich. +* Telemetrie: Sampling-Intervall für Live-Ticker und Limit pro Sekunde definieren. \ No newline at end of file diff --git a/doc/docs/konzept_hardware.md b/doc/docs/konzept_hardware.md deleted file mode 100644 index 386a0d6..0000000 --- a/doc/docs/konzept_hardware.md +++ /dev/null @@ -1,118 +0,0 @@ -# Hardware-Konzept - -## 1. Systemübersicht - -Das Lasertag-System besteht aus einer hierarchischen Architektur, bei der ein Leader-Element mehrere Westeneinheiten mit zugeordneten Waffensystemen steuert. - -```mermaid -graph TD - Leader((Leader)) - - Leader --> Weste1[Weste 1] - Leader --> Weste2[Weste 2] - - Weste1 --> WaffeA(Waffe A) - Weste1 --> WaffeB(Waffe B) - - Weste2 --> WaffeC(Waffe C) - - %% Styling (Optional) - %% style Leader fill:#f96,stroke:#333,stroke-width:2px - %% style Weste1 fill:#bbf,stroke:#333 - %% style Weste2 fill:#bbf,stroke:#333 --> -``` -## 2. Schaltungskomponenten - -### 2.1 LED-Treiber - -#### Grundkonzept - -Der LED-Treiber realisiert eine präzise Konstantstromquelle als Hybridschaltung aus PNP- und NPN-Transistoren. Diese Architektur ermöglicht eine stabile und effiziente Ansteuerung von Infrarot-Leuchtdioden mit definierten Stromwerten. - -![LED DRIVER](img/concept_hardware_led_driver.svg) - -#### Stromeinstelling - -Der Zielstrom wird über den Messwiderstand $R_{set}$ eingestellt. Die Berechnung folgt der Formel: - -$$R_{set} = \frac{0,65V}{I_{LED}}$$ - -Die folgenden Tabelle zeigt typische Stromwerte, die erforderlichen Widerstände und die entsprechenden Anwendungsfälle: - -| Stromstärke ($I_{LED}$) | Widerstand ($R_{set}$) | Ausgangsleistung ($P_{min}$) | Einsatzbereich | -| :--- | :--- | :--- | :--- | -| 0,5 A | 1,30 $\Omega$ | 0,5 W | Standard / Nahkampf | -| 1,0 A | 0,65 $\Omega$ | 1,0 W | Hohe Reichweite (SFH 4550) | -| 2,0 A | 0,33 $\Omega$ | 2,0 W | Extrem hohe Leistung (Pulsbetrieb) | -| 3,0 A | 0,22 $\Omega$ | 3,0 W | Scharfschützen-Modus (Oslon Black) | - -#### Thermische Betrachtung - -Im Lasertag-Betrieb werden die Infrarot-Signale hochfrequent moduliert (beispielsweise mit 38 kHz). Dies führt zu einem signifikant geringeren mittleren Wärmeeintrag in den Messwiderstand als eine kontinuierliche Strombelastung suggeriert: - -$$P_{avg} = (R_{set} \cdot I_{LED}^2) \cdot \text{Duty Cycle}$$ - -!!! info "Bedeutung der Widerstandsspezifikation" - Obwohl die Duty-Cycle-Modulation die durchschnittliche Verlustleistung reduziert, müssen Widerstände für $R_{set}$ für die auftretenden Stromspitzen ausgelegt sein. Wir empfehlen impulsfeste Typen (Metallschicht- oder Drahtwiderständen), um die Stromspitzen bis zu 3 A ohne Materialermüdung zu verkraften. - -#### Spannungsversorgung und Headroom-Anforderungen - -Die Konstantstromquelle benötigt eine Mindestverspannung zwischen Versorgung und Ausgang, um präzise die Sollstromstärke zu halten. Diese sogenannte Headroom-Spannung errechnet sich aus: - -$$V_{CC} > V_{f(\text{LED})} + 0,65V + 1,0V_{\text{Headroom}}$$ - -**Kritischer Aspekt bei Lithium-Ionen-Akkus:** Die Akkuspannung sinkt während der Entladung kontinuierlich. Unterschreitet $V_{CC}$ den erforderlichen Schwellwert, bricht die Regelung zusammen und der LED-Strom kann die Sollvorgabe nicht mehr erreichen. Dies führt zu einer drastischen Reduktion der Reichweite des Senders. - -Die Minimalspannung für stabilen Betrieb wird bestimmt durch: - -$$V_{CC,\text{min}} = V_{f(\text{LED})} + V_{R_{set}} + V_{\text{Headroom}}$$ - -Die folgende Tabelle zeigt die erforderlichen Minimalspannungen für verschiedene Stromvorgaben und die Eignung unterschiedlicher Akkusysteme: - -| Stromstärke ($I_{LED}$) | Typ. LED-Spannung ($V_{f}$) | Erforderliche Spannung ($V_{CC,\text{min}}$) | Akku-Empfehlung | -| :--- | :--- | :--- | :--- | -| 0,5 A | ~2,0 V | 3,65 V | 1S (nur bei voller Ladung) | -| 1,0 A | ~2,4 V | 4,05 V | 2S empfohlen | -| 2,0 A | ~2,8 V | 4,45 V | 2S erforderlich | -| 3,0 A | ~3,2 V | 4,85 V | 2S erforderlich | - -!!! warning "1S-System: Einschränkungen unter Last" - Ein einzelner 1S Li-Po Akku sinkt unter hohen Stromlasten schnell auf 3,4 V bis 3,6 V ab. Für konstante Reichweite bei Strömen ab 1 A ist ein 2S-System daher technisch überlegen. - -#### 2S-Akkusystem: Komplexität und Lösungsansätze - -Ein 2S-Akkusystem bietet zwar Spannungsstabilität, erfordert jedoch anspruchsvollere Schutz- und Überwachungsfunktionen: - -- **Laden:** Moderne 2S-Ladechips mit integriertem Balancing (beispielsweise der IP2326) ermöglichen vereinfachte Ladevorgänge. -- **Zellenschutz:** Ein Zellenschutz-IC wie der HY2120-CB in Kombination mit einem Dual-Channel MOSFET (beispielsweise FS8205A) verhindert Über- und Unterspannungszustände. -- **Fuel Gauge:** Spezielle Fuel-Gauge-ICs für 2S-Systeme sind selten oder komplex. Als praktische Alternative wird eine Spannungsteiler-ADC-Messung zur Ladezustandsabschätzung eingesetzt. Der Spannungsteiler muss durch ein Schaltgattersystem steuerbar sein. - -### 2.2 Akku-Überwachung (Fuel Gauge) - -#### Spannungsmessung bei 2S-Akkus - -Für 2S-Akkusysteme mit Spannungen bis 8,4 V wird die Akkuspannung über einen Spannungsteiler auf den ADC-Eingangspegel reduziert. Dieser Messwert dient zur Ladezustandsabschätzung und Fehlerdiagnose. - -#### Schaltungskomponenten - -| Komponente | Wert | Funktion | -| :--- | :--- | :--- | -| $R_1$ | 100 k$\Omega$ | Spannungsteiler – oberer Zweig | -| $R_2$ | 47 k$\Omega$ | Spannungsteiler – unterer Zweig | -| $C_1$ | 100 nF | Glättungskondensator am ADC-Eingang | - -#### Softwarelogik - -Die Ladezustandsbestimmung erfolgt in drei Schritten: - -1. **ADC-Konvertierung:** Der Rohwert des ADC-Eingangs wird eingelesen. - -2. **Spannungsrückrechnung:** Die Realspannung wird aus dem ADC-Wert berechnet: - $V_{\text{bat}} = V_{\text{adc}} \cdot \frac{R_1 + R_2}{R_2}$ - -3. **Ladezustand-Mapping:** Die Batteriespannung wird auf einen prozentualen Ladezustand abgebildet: - - - **6,0 V** → 0 % (Entladungsschutz aktiv) - - **8,4 V** → 100 % (vollständig geladen) - - Für höhere Genauigkeit können mehrere Messpunkte verwendet und linear interpoliert werden. diff --git a/doc/hardware.md b/doc/hardware.md new file mode 100644 index 0000000..87f8633 --- /dev/null +++ b/doc/hardware.md @@ -0,0 +1,56 @@ +# Hardware-Konzept + +Dieses Dokument beschreibt die physischen Komponenten des Lasertag-Systems. Alle Knoten basieren auf dem Nordic nRF52840 SoC. + +## 1. Waffe (Weapon Unit) + +Die Waffe ist das primäre Interaktionsgerät. Sie muss robust und reaktionsschnell sein. + +* **Controller:** nRF52840 (Dongle oder Modul). +* **IR-Sender:** + * High-Power IR-LED (940nm oder 850nm). + * Optik/Linse zur Bündelung des Strahls (Reichweite > 50m). + * Transistor-Treiberstufe für hohe Impulsströme. +* **Feedback:** + * **Muzzle Flash:** Helle weiße/gelbe LED an der Mündung (sichtbares Feedback). + * **Haptik:** Vibrationsmotor (aktiv bei Schuss). + * **Audio:** Lautsprecher/Piezo für Schussgeräusche ("Piu Piu") und "Leer"-Klicken. +* **Eingabe:** + * **Abzug (Trigger):** Taster. + * **Nachladen (Reload):** Taster am Magazinschacht oder Boden. + * **Modus-Wahl:** Optionaler Schalter für Feuermodus (Einzel/Auto). +* **Stromversorgung:** 2S LiPo (7.4V) mit Step-Down auf 3.3V. + +## 2. Weste (Player Hub) + +Die Weste ist die zentrale Recheneinheit des Spielers und trägt die Sensorik. + +* **Controller:** nRF52840 DK oder Custom Board. +* **Sensorik (IR-Empfänger):** + * Verteilt auf 3 Gruppen für 360° Abdeckung. + * **Kopf:** 3 Sensoren (Stirn, Links, Rechts) an Stirnband/Helm. + * **Torso:** Sensoren an Brust und Rücken. + * **Schultern:** Optionale Sensoren an den Seiten. + * *Technik:* TSOP4838 oder kompatible 38kHz Empfänger. +* **Beleuchtung (Status):** + * Adressierbare RGB-LEDs (WS2812B) an den Sensor-Positionen. + * Funktion: Teamfarbe anzeigen, Treffer blinken, "Zombie"-Status (Grün). +* **Audio:** + * Leistungsstärkerer Lautsprecher für Sprachausgabe ("Game Over", "Respawn in 10s"). +* **Verbindung:** + * Zentrale Box am Rücken mit Steckverbindern zu den Sensorgruppen. + +## 3. Leader Box (Game Controller) + +Die Leader Box dient zur Spielsteuerung und als Infrastruktur-Knoten. + +* **Controller:** nRF52840. +* **Modi (Hardware-Schalter):** + * 2 DIP-Schalter zur Wahl von Leader / Repeater / Base. +* **Ausstattung:** + * **IR-Empfänger:** Um als Ziel (Base) zu fungieren. + * **RGB-LEDs:** Großflächige Anzeige der Base-Farbe (wer hält die Base?). + * **Bluetooth:** Dient als Gateway zum Smartphone des Spielleiters. +* **Stromversorgung:** Großer Akku für lange Laufzeit (da oft stationär ohne Stromnetz). + +*Stand: 03.04.2025* \ No newline at end of file diff --git a/doc/mkdocs.yml b/doc/mkdocs.yml index 447206f..0a1d6a1 100644 --- a/doc/mkdocs.yml +++ b/doc/mkdocs.yml @@ -4,7 +4,8 @@ site_url: https://gitea.iten.pro/edi/lasertag nav: - Übersicht: index.md - Konzept: - - Software: konzept_hardware.md + - Hardware: konzept/hardware.md + - Software: konzept/software.md - Planung: planung.md theme: diff --git a/doc/software.md b/doc/software.md new file mode 100644 index 0000000..39daa19 --- /dev/null +++ b/doc/software.md @@ -0,0 +1,194 @@ +# Software-Konzept & Spielablauf + +Dieses Dokument beschreibt die Software-Architektur, die Rollenverteilung und die Kommunikationsabläufe des Lasertag-Systems. + +## 1. System-Rollen & Hardware-Typen + +Das System basiert auf nRF52840-Chips, die über OpenThread (802.15.4) kommunizieren. + +### A. Leader Box (Game Controller) +* **Funktion:** Zentrale Spielsteuerung, Zeitgeber, Gateway zur Smartphone-App. +* **Modi (wählbar via DIP-Schalter):** + * `00` **Leader:** Spielleiter, BLE-Gateway, sammelt Punkte. + * `01` **Repeater:** Router im Mesh zur Reichweitenverlängerung (z.B. am Baum). + * `11` **Base:** Interaktives Ziel (z.B. für "Domination"-Modus). + +### B. Weste (Player Hub) +* **Funktion:** Zentrale Einheit des Spielers. Verwaltet Lebenspunkte, empfängt Treffer, steuert Audio. +* **Kommunikation:** Hält die Verbindung zur Waffe (Pairing) und zum Leader. + +### C. Waffe +* **Funktion:** Aussenden der IR-Signale, haptisches Feedback, Muzzle-Flash. +* **Logik:** Sendet "Schuss"-Events, empfängt "Sperren"-Befehle von der Weste (wenn tot). + +--- + +## 2. Provisionierung & Setup (Lobby-Phase) + +Bevor das Spiel startet, müssen Geräte dem Netzwerk beitreten und Spielern zugeordnet werden. + +### Schritt 1: Netzwerk-Beitritt (Provisioning) +* **Szenario:** Neue Hardware wird zum ersten Mal verwendet. +* **Ablauf:** + 1. Spielleiter verbindet App via BLE mit **Leader Box**. + 2. Leader Box öffnet das Thread-Netzwerk (Commissioning). + 3. Neue Geräte (Waffe/Weste) werden in den Pairing-Modus versetzt (z.B. Tastenkombination). + 4. Geräte erhalten Netzwerk-Credentials und treten dem Mesh bei. + +### Schritt 2: Spieler-Konfiguration (Assignment) +* **Ziel:** Zuordnung von Hardware zu einer logischen `PlayerID` und einem `Team`. +* **Identifikation:** Jedes nRF52-Board hat eine eindeutige **EUI-64** (MAC). +* **Ablauf:** + 1. App scannt **QR-Code** oder **NFC-Tag** an der Weste/Waffe. + 2. Payload: Enthält die EUI-64 Adresse. + 3. App sendet Konfiguration an Leader Box: `EUI-64 -> {PlayerID: 5, Team: Rot, Name: "Rambo"}`. + 4. **Waffen-Setup:** Waffe meldet ihren Typ (z.B. "Sniper") an Leader. + 5. Leader sendet Konfigurations-Paket (CoAP Unicast) an das Gerät: + * **Weste:** Erhält PlayerID, TeamID, MaxHealth. + * **Waffe:** Erhält Damage-Wert, Nachladezeit, Magazingröße. + +--- + +## 3. Spielablauf (Game Loop) + +### Phase A: Vorbereitung +* **Leader:** Sendet Multicast `GAME_STATE_LOBBY`. +* **Geräte:** Spielen Idle-Animation ab, warten auf Start. +* **Check:** Leader kann "Ping" an alle senden, um Anwesenheit zu prüfen. + +### Phase B: Countdown +* **Leader:** Sendet Multicast `GAME_START_COUNTDOWN` (Payload: 10 sek). +* **Westen:** Zählen laut herunter: "10, 9, 8...". + +### Phase C: Spiel läuft (Running) +* **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` + `TeamID`). + 2. Weste B empfängt IR-Signal. + 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). + +### Phase D: Spieler eliminiert +* **Bedingung:** Lebenspunkte <= 0. +* **Weste B:** + * Spielt "Dead"-Sound. + * Leuchtet dauerhaft in Teamfarbe (oder aus). + * Sendet CoAP Unicast an **eigene Waffe**: `CMD_DISABLE`. +* **Respawn (falls aktiv):** + * Nach Zeitablauf (z.B. 30s) sendet Weste an Waffe: `CMD_ENABLE`. + * Lebenspunkte werden zurückgesetzt. + +### Phase E: Spielende & Auswertung +* **Leader:** Sendet Multicast `GAME_STATE_FINISHED`. +* **Ablauf:** + 1. Alle Spieler kommen zusammen. + 2. Spielleiter drückt in App "Daten abrufen". + 3. Leader Box fragt nacheinander (Unicast) alle bekannten Westen ab: `GET /game/log`. + 4. Westen übertragen ihre Treffer-Historie. + 5. App berechnet Highscores, MVP, Trefferquoten. + +--- + +## 4. Spielmodi + +Die Logik für die Modi wird primär auf den Westen implementiert (Regelwerk), gesteuert durch Flags vom Leader. + +### Team Deathmatch +* Klassisch Rot gegen Blau. +* Friendly Fire konfigurierbar (an/aus). +* Siegbedingung: Meiste Kills oder wenigste Tode nach Zeitablauf. + +### Last Man Standing (Free-for-all) +* Jeder gegen Jeden. +* Keine Teams (oder jeder hat eigene Team-ID). +* Kein Respawn. + +### Zombie (Infected) +* **Start:** 1 Spieler ist "Zombie" (Team Grün), Rest "Mensch" (Team Rot). +* **Regel:** + * Zombie hat unendlich Leben (oder sehr viel). + * Mensch hat 1 Leben. + * Wird Mensch getroffen -> Wechselt Team zu Zombie (Weste leuchtet grün, Waffe sendet ab jetzt Zombie-ID). + * Wird Zombie getroffen -> "Stunned" (Waffe 5s gesperrt). +* **Ziel:** Überleben bis Zeitablauf. + +### Base Domination +* **Hardware:** Leader-Boxen im Modus `11` (Base) verteilt im Gelände. +* **Ablauf:** + * Spieler schießt auf Base-Box. + * Base-Box wechselt Farbe zu Teamfarbe des Schützen. + * Base-Box zählt Zeit für das haltende Team. + * Am Ende fragt Leader alle Base-Boxen ab: "Wie lange warst du Rot? Wie lange Blau?". + +--- + +## 5. Technische Spezifikation (API & Datenstrukturen) + +Die Kommunikation erfolgt über CoAP (UDP). Alle Payloads sind binär (`__packed` C-Structs, Little Endian für nRF52, aber Network Byte Order Big Endian empfohlen für Portabilität - hier vereinfacht Little Endian da homogene Hardware). + +### 5.1 CoAP Endpunkte + +| Ressource | Methode | Typ | Beschreibung | Payload | +| :--- | :--- | :--- | :--- | :--- | +| `game/state` | PUT | Multicast | Globaler Spielstatus (Start/Stop/Zeit) | `struct game_state_packet` | +| `game/conf` | PUT | Unicast | Konfiguration für einen Spieler | `struct player_config_packet` | +| `game/hit` | POST | Unicast | Treffer-Meldung (Live-Ticker) | `struct hit_report_packet` | +| `game/wconf` | PUT | Unicast | Konfiguration für eine Waffe | `struct weapon_config_packet` | +| `game/log` | GET | Unicast | Abruf der gespeicherten Trefferdaten | `struct flash_log_entry[]` | + +### 5.2 Datenstrukturen + +#### Spielstatus (Multicast) +```c +struct game_state_packet { + uint8_t state; // 0=Idle, 1=Lobby, 2=Running, 3=Paused, 4=Finished + uint8_t game_mode; // 0=TeamDeathmatch, 1=Zombie, 2=Base + uint16_t game_id; // Rolling Counter zur Deduplizierung + uint16_t remaining_sec; // Restzeit in Sekunden + uint8_t flags; // Bitmaske (z.B. FriendlyFire) +} __packed; +``` + +#### Spieler-Konfiguration (Provisioning) +```c +struct player_config_packet { + uint16_t player_id; // Logische ID (1-65535) + uint8_t team_id; // 0=Rot, 1=Blau, 2=Grün (Zombie), ... + uint8_t health_max; // Maximale Lebenspunkte + char name[16]; // Anzeigename (null-terminated) +} __packed; +``` + +#### Waffen-Konfiguration +```c +struct weapon_config_packet { + uint8_t base_damage; // Schaden pro Schuss + uint16_t reload_time_ms;// Zeit für Nachladen + uint8_t magazine_size; // Schuss pro Magazin +} __packed; +``` + +#### Treffer-Bericht (Live & Log) +```c +struct hit_report_packet { + uint32_t timestamp; // ms seit Spielstart + uint16_t shooter_id; // ID des Schützen (aus IR) + uint16_t victim_id; // Eigene ID + uint8_t damage; // Erlittener Schaden + uint8_t hit_location; // 0=Unbekannt, 1=Kopf, 2=Brust, 3=Rücken +} __packed; +``` + +--- + +## 6. IR-Protokoll (Physical Layer) + +Das IR-Signal nutzt eine 38kHz Trägerfrequenz (NEC-ähnlich). +Payload (32-bit): +* `8 bit` Protokoll-ID (Magic Byte zur Unterscheidung von Fernbedienungen) +* `16 bit` Shooter ID +* `8 bit` Info (4 bit Team, 4 bit Damage Class) \ No newline at end of file diff --git a/firmware/apps/weapon/main.c b/firmware/apps/weapon/main.c new file mode 100644 index 0000000..bec315c --- /dev/null +++ b/firmware/apps/weapon/main.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include + +/* Unsere neue Library */ +#include "game_logic.h" + +LOG_MODULE_REGISTER(weapon_app, LOG_LEVEL_INF); + +/* Spiel-Kontext */ +static struct game_ctx game; + +/* Forward Declarations */ +static void on_button_changed(uint32_t button_state, uint32_t has_changed); + +/* --- Game Logic Callbacks --- */ + +static void on_game_state_change(enum game_state new_state) +{ + LOG_INF("APP: Spielstatus geändert -> %d", new_state); + + switch (new_state) { + case GAME_STATE_RUNNING: + dk_set_led_on(DK_LED1); // LED an wenn Spiel läuft + break; + case GAME_STATE_FINISHED: + dk_set_led_off(DK_LED1); + // Blinken oder ähnliches + break; + default: + dk_set_led_off(DK_LED1); + break; + } +} + +static void on_hit_received(uint16_t shooter_id) +{ + LOG_WARN("APP: AUA! Getroffen von Spieler %d. Leben: %d", shooter_id, game.health); + + // Visuelles Feedback: LED 2 blinkt kurz + dk_set_led_on(DK_LED2); + k_msleep(200); + dk_set_led_off(DK_LED2); + + // TODO: Hier später CoAP Nachricht an Leader senden! + // send_hit_report_to_leader(...); +} + +static void on_shot_fired(void) +{ + LOG_INF("APP: PENG! Schuss abgefeuert."); + // TODO: Hier IR-Protokoll senden (NEC/RC5) +} + +/* --- Hardware Callbacks --- */ + +static void on_button_changed(uint32_t button_state, uint32_t has_changed) +{ + // Button 1: Schießen + if ((has_changed & DK_BTN1_MSK) && (button_state & DK_BTN1_MSK)) { + if (game.current_state == GAME_STATE_RUNNING) { + on_shot_fired(); + } else { + LOG_INF("Schuss blockiert - Spiel läuft nicht."); + } + } + + // Button 2: Treffer simulieren (Self-Hit Test) + if ((has_changed & DK_BTN2_MSK) && (button_state & DK_BTN2_MSK)) { + LOG_INF("Simuliere Treffer durch Spieler 99..."); + struct game_hit_packet hit_packet; + + // Wir tun so, als hätte der IR-Sensor Spieler 99 erkannt + if (game_logic_register_hit(99, &hit_packet)) { + // Wenn Treffer gültig war (Spiel läuft, wir leben noch), haben wir jetzt ein Paket + // das wir via Thread versenden könnten. + LOG_INF("Treffer registriert! Damage: %d", hit_packet.damage); + } + } +} + +/* --- Main --- */ + +void main(void) +{ + LOG_INF("Lasertag Weapon Start"); + + int err = dk_buttons_init(on_button_changed); + if (err) { + LOG_ERR("Buttons konnten nicht initialisiert werden (err %d)", err); + } + + // Game Logic Setup + game.on_state_change = on_game_state_change; + game.on_hit_received = on_hit_received; + + // Initialisiere als Spieler mit ID aus Kconfig (oder NVS später) + game_logic_init(&game, CONFIG_LASERTAG_PLAYER_ID_DEFAULT); + + // Zum Testen setzen wir den Status manuell auf RUNNING, + // bis wir das Start-Signal vom Leader via Thread empfangen. + struct game_state_packet fake_start = {.state = GAME_STATE_RUNNING}; + game_logic_handle_state_update(&fake_start); + + while (1) { + k_sleep(K_FOREVER); + } +} \ No newline at end of file diff --git a/firmware/apps/weapon/prj.conf b/firmware/apps/weapon/prj.conf index 4b3c3e3..13d39a9 100644 --- a/firmware/apps/weapon/prj.conf +++ b/firmware/apps/weapon/prj.conf @@ -1 +1,20 @@ -CONFIG_LASERTAG_UTILS=y +# Logging +CONFIG_LOG=y +CONFIG_LASERTAG_WEAPON_LOG_LEVEL_INF=y + +# Network / OpenThread +CONFIG_NETWORKING=y +CONFIG_NET_L2_OPENTHREAD=y +CONFIG_OPENTHREAD_COAP=y + +# Hardware (Buttons & LEDs) +CONFIG_DK_LIBRARY=y + +# Lasertag Game Logic +CONFIG_LASERTAG_GAME_LOGIC=y +CONFIG_LASERTAG_ROLE_PLAYER=y +CONFIG_LASERTAG_PLAYER_ID_DEFAULT=2 + +# Optional: Shell für Debugging +CONFIG_SHELL=y +CONFIG_OPENTHREAD_SHELL=y \ No newline at end of file