add models
This commit is contained in:
86
README.md
86
README.md
@@ -4,43 +4,69 @@ Dieses Projekt ist eine hochoptimierte KI-Steuerung für die DJI Tello Drohne (u
|
|||||||
|
|
||||||
## 🚀 Hauptmerkmale
|
## 🚀 Hauptmerkmale
|
||||||
- **Hybrid AI Engine**: Nutzt **YuNet** (Face Detection), **MiDaS** (Depth Estimation) und **MobileNetV3** (ReID) – alle via **ONNX Runtime** für maximale FPS.
|
- **Hybrid AI Engine**: Nutzt **YuNet** (Face Detection), **MiDaS** (Depth Estimation) und **MobileNetV3** (ReID) – alle via **ONNX Runtime** für maximale FPS.
|
||||||
- **Multithreading**: Kamera-Stream und KI-Verarbeitung laufen in getrennten Threads. Das Videobild bleibt flüssig, egal wie schwer die KI arbeitet.
|
- **Sport-Modus**: Aggressives 3-Achsen-Tracking für schnelle Verfolgungsjagden.
|
||||||
- **Visual Fingerprinting (ReID)**: Die Drohne erstellt einen digitalen Fingerabdruck einer fixierten Person und findet sie automatisch wieder, wenn sie kurz aus dem Bild verschwindet.
|
- **Visual Fingerprinting (ReID)**: Erkennt fixierte Personen wieder, auch wenn sie das Bild kurz verlassen.
|
||||||
- **Intelligente Verfolgung**: Aktive Suche in Verschwindungsrichtung und aggressiver Verfolgungsmodus.
|
- **Multithreading**: Flüssiges Kamerabild durch Trennung von Video-Stream und KI-Logik.
|
||||||
- **Echtzeit-HUD**: Professionelles Display mit Telemetrie, AI-Tiefenkarte und Radar-Zonen zur Hindernisvermeidung.
|
- **Simulator inklusive**: Eine integrierte Ursina-Umgebung zum gefahrlosen Testen.
|
||||||
- **Rate Limiting**: Kontrollierter Datenfluss (10Hz) zum Tello-SDK für maximale Verbindungsstabilität.
|
|
||||||
|
|
||||||
## 🕹 Steuerung
|
## 🛠 Installation
|
||||||
Klicke mit der **Maus** direkt in das Videobild, um eine Person zu fixieren (**Lock-ON**).
|
|
||||||
|
|
||||||
### Tastatur-Belegung:
|
1. **Python-Umgebung**: Empfohlen wird Python 3.10 bis 3.12.
|
||||||
|
2. **Abhängigkeiten installieren**:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
3. **Modelle prüfen**: Stelle sicher, dass im Ordner `models/` folgende Dateien liegen:
|
||||||
|
- `face_detection_yunet.onnx`
|
||||||
|
- `midas_small.onnx`
|
||||||
|
- `reid_mobilenet.onnx`
|
||||||
|
|
||||||
|
## 🚀 Starten der Drohne
|
||||||
|
|
||||||
|
### A) Im Simulator (Standard)
|
||||||
|
1. Öffne die Datei `run.py`.
|
||||||
|
2. Stelle sicher, dass `use_real_tello=False` eingestellt ist.
|
||||||
|
3. Starte das Programm:
|
||||||
|
```bash
|
||||||
|
python run.py
|
||||||
|
```
|
||||||
|
4. Das Simulator-Fenster und das KI-Pilot-Fenster öffnen sich automatisch.
|
||||||
|
|
||||||
|
### B) Mit der echten DJI Tello
|
||||||
|
1. Schalte deine Tello ein und verbinde deinen PC mit dem WLAN der Drohne (z.B. `TELLO-XXXXXX`).
|
||||||
|
2. Öffne die Datei `run.py` und ändere die Zeile zu:
|
||||||
|
```python
|
||||||
|
app = FaceTrackingApp(use_real_tello=True)
|
||||||
|
```
|
||||||
|
3. Starte das Programm:
|
||||||
|
```bash
|
||||||
|
python run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🕹 Bedienung im Flug
|
||||||
|
|
||||||
|
Sobald das Video-Fenster erscheint:
|
||||||
|
1. **Klicke mit der Maus** in das Fenster, um den Fokus zu aktivieren.
|
||||||
|
2. Drücke **'T'** zum Starten (Takeoff).
|
||||||
|
3. **Tracking aktivieren**: Klicke mit der Maus auf ein erkanntes Gesicht/Person oder drücke **'K'**, um den nächsten erkannten Kopf zu fixieren (Lock-ON).
|
||||||
|
|
||||||
|
### Wichtige Tasten:
|
||||||
| Taste | Aktion |
|
| Taste | Aktion |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| **T** | **Takeoff** (Starten) - Einmal drücken und kurz warten |
|
| **T** | **Takeoff** (Abheben) |
|
||||||
| **L** | **Land** (Landen) |
|
| **L** | **Land** (Landen) |
|
||||||
| **M** | Wechsel zwischen **Manuell** und **KI-Modus** |
|
| **2** | **Sport-Modus** (An/Aus) - Schnelleres Tracking auf allen Achsen |
|
||||||
| **K** | Lock-ON Trigger aktivieren / Fixierung löschen |
|
| **M** | **Manueller Modus** (KI stoppt die Steuerung) |
|
||||||
| **Space**| **Not-Aus** (Stoppt alle Motoren sofort) |
|
| **Space**| **Not-Aus** (Motoren sofort aus) |
|
||||||
| **W/S** | Vorwärts / Rückwärts (Manuell) |
|
| **W/S/A/D**| Vorwärts, Rückwärts, Links, Rechts (Manuell) |
|
||||||
| **A/D** | Links / Rechts (Manuell) |
|
|
||||||
| **R/F** | Steigen / Sinken (Manuell) |
|
| **R/F** | Steigen / Sinken (Manuell) |
|
||||||
| **E/Z** | Drehen Links / Rechts (Manuell) |
|
| **E/Z** | Drehen Links / Rechts (Manuell) |
|
||||||
| **1** | Automatisches Drehen (Scan-Modus) an/aus |
|
| **Enter**| Programm sicher beenden |
|
||||||
| **Enter**| Programm beenden |
|
|
||||||
|
|
||||||
## 🏗 Architektur
|
## 🏗 Architektur & Performance
|
||||||
- `drone_pilot/main.py`: Das Herzstück. Verwaltet Threads, UI-Events und die Hauptschleife.
|
- **AI-Worker Thread**: Verarbeitet alle Modelle parallel zum Haupt-Thread.
|
||||||
- `drone_pilot/vision.py`: Die KI-Engine. Lädt ONNX-Modelle und verarbeitet Bilddaten.
|
- **Rate Limiting**: RC-Befehle werden mit 10Hz gesendet, um das SDK-Protokoll nicht zu überlasten.
|
||||||
- `drone_pilot/flight.py`: Der Flug-Controller. Berechnet RC-Vektoren basierend auf KI-Ergebnissen.
|
- **ONNX Acceleration**: Nutzt CPU-Optimierungen, die bis zu 5x schneller als Standard-PyTorch sind.
|
||||||
- `drone_pilot/ui.py`: HUD-Renderer für das OpenCV-Fenster.
|
|
||||||
- `drone_pilot/config.py`: Zentrale Konfiguration für Geschwindigkeiten und Schwellenwerte.
|
|
||||||
|
|
||||||
## 🛠 Installation & Start
|
|
||||||
1. Installiere die Abhängigkeiten: `pip install -r requirements.txt`
|
|
||||||
2. Stelle sicher, dass die Modelle im Ordner `models/` liegen.
|
|
||||||
3. Starte das Programm:
|
|
||||||
- Simulator: `python run.py` (Default: `use_real_tello=False`)
|
|
||||||
- Reale Drohne: Ändere in `run.py` zu `use_real_tello=True`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
*Hinweis: Beim Fliegen mit der realen Drohne immer auf einen Akkustand > 15% achten, da der Startbefehl sonst vom SDK abgelehnt wird.*
|
*Viel Spaß beim Fliegen! Achte bei der echten Drohne immer auf genügend Platz und einen vollen Akku (>15%).*
|
||||||
|
|||||||
1
blaze_face_long_range.tflite
Normal file
1
blaze_face_long_range.tflite
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?><Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Details>No such object: mediapipe-models/face_detector/blaze_face_long_range/float16/latest/blaze_face_long_range.tflite</Details></Error>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# drone_pilot/config.py
|
# drone_pilot/config.py
|
||||||
class Config:
|
class Config:
|
||||||
WIN_NAME = "Tello AI Pilot v2.0 (High Speed)"
|
WIN_NAME = "Tello AI Pilot v2.0 (Extreme Speed)"
|
||||||
WIDTH, HEIGHT = 1024, 720
|
WIDTH, HEIGHT = 1024, 720
|
||||||
|
|
||||||
TARGET_ALTITUDE = 1.5
|
TARGET_ALTITUDE = 1.5
|
||||||
@@ -8,21 +8,28 @@ class Config:
|
|||||||
TARGET_PERSON_SIZE = 400
|
TARGET_PERSON_SIZE = 400
|
||||||
ALT_THRESHOLD = 0.12
|
ALT_THRESHOLD = 0.12
|
||||||
|
|
||||||
YAW_GAIN = 0.08 # Reduced for smoother rotation
|
# Normal Mode Gains
|
||||||
FORWARD_GAIN = 1.5 # Kept high for fast pursuit
|
YAW_GAIN = 0.12
|
||||||
|
FORWARD_GAIN = 1.5
|
||||||
ALT_GAIN = 40
|
ALT_GAIN = 40
|
||||||
|
|
||||||
|
# Sport Mode Gains (Much more aggressive)
|
||||||
|
SPORT_YAW_GAIN = 0.25
|
||||||
|
SPORT_FB_GAIN = 2.0
|
||||||
|
SPORT_LR_GAIN = 0.6
|
||||||
|
|
||||||
DEPTH_THRESHOLD = 0.90
|
DEPTH_THRESHOLD = 0.90
|
||||||
OBSTACLE_TOF_CM = 70
|
OBSTACLE_TOF_CM = 70
|
||||||
FACE_DEADZONE = 30 # Slightly larger deadzone for stability
|
FACE_DEADZONE = 20
|
||||||
FACE_ROT_ONLY = 100
|
FACE_ROT_ONLY = 80
|
||||||
PERSON_CONF_THRESHOLD = 0.5
|
PERSON_CONF_THRESHOLD = 0.5
|
||||||
SMOOTHING_ALPHA = 0.35 # High directness, but slightly more damped than extreme
|
SMOOTHING_ALPHA = 0.35
|
||||||
|
|
||||||
class Colors:
|
class Colors:
|
||||||
GREEN = (0, 255, 0)
|
GREEN = (0, 255, 0)
|
||||||
RED = (0, 0, 255)
|
RED = (0, 0, 255)
|
||||||
BLUE = (255, 0, 0)
|
BLUE = (255, 0, 0)
|
||||||
|
PURPLE = (255, 0, 255)
|
||||||
WHITE = (255, 255, 255)
|
WHITE = (255, 255, 255)
|
||||||
BLACK = (0, 0, 0)
|
BLACK = (0, 0, 0)
|
||||||
HUD_BG = (10, 10, 10)
|
HUD_BG = (10, 10, 10)
|
||||||
|
|||||||
@@ -4,19 +4,24 @@ from typing import List, Tuple, Dict
|
|||||||
from .config import Config
|
from .config import Config
|
||||||
|
|
||||||
class FlightController:
|
class FlightController:
|
||||||
|
"""
|
||||||
|
Verantwortlich für die Berechnung der Flugvektoren basierend auf KI-Ergebnissen.
|
||||||
|
Unterstützt Normal-Modus (sequenziell) und Sport-Modus (simultan/LR).
|
||||||
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.last_sent_rc = [0, 0, 0, 0]
|
self.last_sent_rc = [0, 0, 0, 0]
|
||||||
self.smooth_face = None
|
self.smooth_face = None
|
||||||
self.search_start = time.time()
|
self.search_start = time.time()
|
||||||
self.status = "INITIALIZING"
|
self.status = "INITIALIZING"
|
||||||
|
|
||||||
# Memory for lost targets
|
# Speicher für verloren gegangene Ziele
|
||||||
self.last_target_side = 0 # -1 for left, 1 for right
|
self.last_target_side = 0
|
||||||
self.lost_time = 0
|
self.lost_time = 0
|
||||||
|
|
||||||
def calculate(self,
|
def calculate(self,
|
||||||
faces: List[Tuple],
|
faces: List[Tuple],
|
||||||
is_manual: bool,
|
is_manual: bool,
|
||||||
|
is_sport: bool, # NEU: Sport-Modus Flag
|
||||||
emergency_stop: bool,
|
emergency_stop: bool,
|
||||||
is_locked: bool,
|
is_locked: bool,
|
||||||
locked_person: Tuple,
|
locked_person: Tuple,
|
||||||
@@ -29,7 +34,6 @@ class FlightController:
|
|||||||
|
|
||||||
lr, fb, ud, yv = 0, 0, 0, 0
|
lr, fb, ud, yv = 0, 0, 0, 0
|
||||||
|
|
||||||
# Face smoothing for UI/Visuals
|
|
||||||
if len(faces) > 0:
|
if len(faces) > 0:
|
||||||
target = max(faces, key=lambda f: f[2] * f[3])
|
target = max(faces, key=lambda f: f[2] * f[3])
|
||||||
if self.smooth_face is None: self.smooth_face = target
|
if self.smooth_face is None: self.smooth_face = target
|
||||||
@@ -42,13 +46,13 @@ class FlightController:
|
|||||||
self.status = "EMERGENCY STOP"
|
self.status = "EMERGENCY STOP"
|
||||||
return (0, 0, 0, 0), self.status
|
return (0, 0, 0, 0), self.status
|
||||||
|
|
||||||
# Obstacle Avoidance (always active if flying)
|
# Hindernisvermeidung
|
||||||
center_blocked = zones["CENTER"] or tof < Config.OBSTACLE_TOF_CM
|
center_blocked = zones["CENTER"] or tof < Config.OBSTACLE_TOF_CM
|
||||||
if center_blocked:
|
if center_blocked:
|
||||||
self.status = "AVOIDING OBSTACLE"
|
self.status = "AVOIDING OBSTACLE"
|
||||||
yv = 80 if zone_scores["LEFT"] < zone_scores["RIGHT"] else -80
|
yv = 80 if zone_scores["LEFT"] < zone_scores["RIGHT"] else -80
|
||||||
fb = -30
|
fb = -30
|
||||||
return self._smooth(lr, fb, ud, yv)
|
return self._smooth(0, fb, 0, yv)
|
||||||
|
|
||||||
if is_manual:
|
if is_manual:
|
||||||
self.status = "MANUAL CONTROL"
|
self.status = "MANUAL CONTROL"
|
||||||
@@ -59,54 +63,57 @@ class FlightController:
|
|||||||
# AI LOGIC
|
# AI LOGIC
|
||||||
if is_locked:
|
if is_locked:
|
||||||
if locked_person is not None:
|
if locked_person is not None:
|
||||||
# Target is visible -> Normal Pursuit
|
|
||||||
self.search_start = time.time()
|
self.search_start = time.time()
|
||||||
self.lost_time = 0
|
self.lost_time = 0
|
||||||
(x, y, w, h) = locked_person
|
(x, y, w, h) = locked_person
|
||||||
center_x = x + w // 2
|
center_x = x + w // 2
|
||||||
err_x = center_x - (Config.WIDTH // 2)
|
err_x = center_x - (Config.WIDTH // 2)
|
||||||
|
|
||||||
# Remember which side it was on
|
|
||||||
self.last_target_side = 1 if err_x > 0 else -1
|
self.last_target_side = 1 if err_x > 0 else -1
|
||||||
|
|
||||||
# Rotation (Yaw) - SMOOTHER
|
if is_sport:
|
||||||
|
# SPORT MODUS: Alles gleichzeitig + LR-Strafing
|
||||||
|
yv = int(np.clip(Config.SPORT_YAW_GAIN * err_x, -100, 100))
|
||||||
|
fb = int(np.clip(Config.SPORT_FB_GAIN * (Config.TARGET_PERSON_SIZE - w), -100, 100))
|
||||||
|
lr = int(np.clip(Config.SPORT_LR_GAIN * err_x, -60, 60))
|
||||||
|
self.status = "SPORT PURSUIT: FULL AXIS"
|
||||||
|
else:
|
||||||
|
# NORMAL MODUS: Sequenziell (Drehen ODER Fliegen)
|
||||||
if abs(err_x) > Config.FACE_DEADZONE:
|
if abs(err_x) > Config.FACE_DEADZONE:
|
||||||
yv = int(np.clip(Config.YAW_GAIN * err_x, -50, 50))
|
yv = int(np.clip(Config.YAW_GAIN * err_x, -50, 50))
|
||||||
|
fb = 0
|
||||||
# Forward/Backward pursuit - EXTREME SPEED
|
self.status = "PURSUIT: AIMING"
|
||||||
alignment_factor = max(0.4, 1.0 - (abs(err_x) / Config.FACE_ROT_ONLY))
|
|
||||||
target_fb = int(np.clip(Config.FORWARD_GAIN * (Config.TARGET_PERSON_SIZE - w), -90, 90))
|
|
||||||
fb = int(target_fb * alignment_factor)
|
|
||||||
|
|
||||||
self.status = "PURSUIT: EXTREME"
|
|
||||||
else:
|
else:
|
||||||
# Target is LOST -> Rapid Search logic
|
yv = 0
|
||||||
|
fb = int(np.clip(Config.FORWARD_GAIN * (Config.TARGET_PERSON_SIZE - w), -80, 80))
|
||||||
|
self.status = "PURSUIT: APPROACHING"
|
||||||
|
else:
|
||||||
|
# Target verloren
|
||||||
if self.lost_time == 0: self.lost_time = time.time()
|
if self.lost_time == 0: self.lost_time = time.time()
|
||||||
elapsed = time.time() - self.lost_time
|
elapsed = time.time() - self.lost_time
|
||||||
|
|
||||||
if elapsed < 10.0: # Search longer and faster
|
search_speed = 60 if is_sport else 40
|
||||||
yv = 40 * self.last_target_side
|
if elapsed < 10.0:
|
||||||
|
yv = search_speed * self.last_target_side
|
||||||
self.status = f"LOST TARGET: SCANNING {'RIGHT' if self.last_target_side > 0 else 'LEFT'}"
|
self.status = f"LOST TARGET: SCANNING {'RIGHT' if self.last_target_side > 0 else 'LEFT'}"
|
||||||
else:
|
else:
|
||||||
self.status = "TARGET LOST: AGGRESSIVE PATROL"
|
self.status = "TARGET LOST: PATROL"
|
||||||
yv = 30
|
yv = 30
|
||||||
|
|
||||||
elif self.smooth_face is not None:
|
elif self.smooth_face is not None:
|
||||||
# Face found but not locked
|
|
||||||
(x, y, w, h) = self.smooth_face
|
(x, y, w, h) = self.smooth_face
|
||||||
err_x = (x + w // 2) - (Config.WIDTH // 2)
|
err_x = (x + w // 2) - (Config.WIDTH // 2)
|
||||||
if abs(err_x) > Config.FACE_DEADZONE:
|
|
||||||
yv = int(np.clip(Config.YAW_GAIN * err_x, -40, 40))
|
yv = int(np.clip(Config.YAW_GAIN * err_x, -40, 40))
|
||||||
self.status = "AWAITING LOCK"
|
self.status = "AWAITING LOCK"
|
||||||
else:
|
else:
|
||||||
# Patrol mode - faster
|
# Patrouille
|
||||||
elapsed = (time.time() - self.search_start) % 6.0
|
elapsed = (time.time() - self.search_start) % 8.0
|
||||||
if elapsed < 2.0:
|
if elapsed < 3.0:
|
||||||
self.status = "PATROL: DASH"
|
self.status = "PATROL: ADVANCE"
|
||||||
fb = 40
|
fb = 35
|
||||||
else:
|
else:
|
||||||
self.status = "PATROL: SCAN"
|
self.status = "PATROL: SCAN"
|
||||||
yv = 30
|
yv = 35
|
||||||
|
|
||||||
return self._smooth(lr, fb, ud, yv)
|
return self._smooth(lr, fb, ud, yv)
|
||||||
|
|
||||||
@@ -117,10 +124,10 @@ class FlightController:
|
|||||||
sud = int(self.last_sent_rc[2] * (1-alpha) + ud * alpha)
|
sud = int(self.last_sent_rc[2] * (1-alpha) + ud * alpha)
|
||||||
syv = int(self.last_sent_rc[3] * (1-alpha) + yv * alpha)
|
syv = int(self.last_sent_rc[3] * (1-alpha) + yv * alpha)
|
||||||
|
|
||||||
if abs(slr) < 2: slr = 0
|
if abs(slr) < 3: slr = 0
|
||||||
if abs(sfb) < 2: sfb = 0
|
if abs(sfb) < 3: sfb = 0
|
||||||
if abs(sud) < 2: sud = 0
|
if abs(sud) < 3: sud = 0
|
||||||
if abs(syv) < 2: syv = 0
|
if abs(syv) < 3: syv = 0
|
||||||
|
|
||||||
self.last_sent_rc = [slr, sfb, sud, syv]
|
self.last_sent_rc = [slr, sfb, sud, syv]
|
||||||
return (slr, sfb, sud, syv), self.status
|
return (slr, sfb, sud, syv), self.status
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class FaceTrackingApp:
|
|||||||
# State Management
|
# State Management
|
||||||
self.is_running = True
|
self.is_running = True
|
||||||
self.is_manual = True
|
self.is_manual = True
|
||||||
|
self.is_sport = False # NEW: Sport Mode flag
|
||||||
self.is_locked = False
|
self.is_locked = False
|
||||||
self.is_taking_off = False
|
self.is_taking_off = False
|
||||||
self.is_flying = False
|
self.is_flying = False
|
||||||
@@ -180,9 +181,10 @@ class FaceTrackingApp:
|
|||||||
self.locked_person_features = feat
|
self.locked_person_features = feat
|
||||||
self.is_locked = True
|
self.is_locked = True
|
||||||
self.lock_trigger = False
|
self.lock_trigger = False
|
||||||
|
self.is_manual = False
|
||||||
break
|
break
|
||||||
|
|
||||||
# UI
|
# UI Graphics
|
||||||
if self.is_locked and self.locked_person:
|
if self.is_locked and self.locked_person:
|
||||||
(x,y,w,h) = self.locked_person
|
(x,y,w,h) = self.locked_person
|
||||||
cv2.rectangle(frame, (x,y), (x+w,y+h), Colors.BLUE, 3)
|
cv2.rectangle(frame, (x,y), (x+w,y+h), Colors.BLUE, 3)
|
||||||
@@ -204,6 +206,7 @@ class FaceTrackingApp:
|
|||||||
rc, status = self.flight_controller.calculate(
|
rc, status = self.flight_controller.calculate(
|
||||||
faces=faces,
|
faces=faces,
|
||||||
is_manual=self.is_manual,
|
is_manual=self.is_manual,
|
||||||
|
is_sport=self.is_sport, # NEW
|
||||||
emergency_stop=self.emergency_stop,
|
emergency_stop=self.emergency_stop,
|
||||||
is_locked=self.is_locked,
|
is_locked=self.is_locked,
|
||||||
locked_person=self.locked_person,
|
locked_person=self.locked_person,
|
||||||
@@ -215,7 +218,8 @@ class FaceTrackingApp:
|
|||||||
manual_rc=active_manual_rc
|
manual_rc=active_manual_rc
|
||||||
)
|
)
|
||||||
|
|
||||||
# Throttle and optimized sending
|
if self.is_sport: status = "SPORT MODE: ACTIVE"
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now - self.last_rc_time >= 0.1:
|
if now - self.last_rc_time >= 0.1:
|
||||||
changed = any(abs(rc[i] - self._prev_rc[i]) > 1 for i in range(4))
|
changed = any(abs(rc[i] - self._prev_rc[i]) > 1 for i in range(4))
|
||||||
@@ -250,7 +254,6 @@ class FaceTrackingApp:
|
|||||||
|
|
||||||
def _handle_takeoff(self):
|
def _handle_takeoff(self):
|
||||||
if self.is_taking_off or self.is_flying: return
|
if self.is_taking_off or self.is_flying: return
|
||||||
|
|
||||||
self.is_taking_off = True
|
self.is_taking_off = True
|
||||||
self.takeoff_error = False
|
self.takeoff_error = False
|
||||||
def _task():
|
def _task():
|
||||||
@@ -265,13 +268,13 @@ class FaceTrackingApp:
|
|||||||
self.takeoff_error = True
|
self.takeoff_error = True
|
||||||
finally:
|
finally:
|
||||||
self.is_taking_off = False
|
self.is_taking_off = False
|
||||||
|
|
||||||
threading.Thread(target=_task, daemon=True).start()
|
threading.Thread(target=_task, daemon=True).start()
|
||||||
|
|
||||||
def _handle_input(self, key: int):
|
def _handle_input(self, key: int):
|
||||||
if key == 13: self.is_running = False
|
if key == 13: self.is_running = False
|
||||||
elif key == 32: self.emergency_stop = not self.emergency_stop
|
elif key == 32: self.emergency_stop = not self.emergency_stop
|
||||||
elif key == ord('m'): self.is_manual = not self.is_manual
|
elif key == ord('m'): self.is_manual = not self.is_manual
|
||||||
|
elif key == ord('2'): self.is_sport = not self.is_sport # Toggle Sport Mode
|
||||||
elif key == ord('k'):
|
elif key == ord('k'):
|
||||||
self.lock_trigger = not self.lock_trigger
|
self.lock_trigger = not self.lock_trigger
|
||||||
self.is_locked = False
|
self.is_locked = False
|
||||||
@@ -287,11 +290,9 @@ class FaceTrackingApp:
|
|||||||
except: pass
|
except: pass
|
||||||
elif key == ord('1'): self.is_rotating = not self.is_rotating
|
elif key == ord('1'): self.is_rotating = not self.is_rotating
|
||||||
|
|
||||||
# Reset manual speed
|
|
||||||
self.m_lr, self.m_fb, self.m_ud, self.m_yv = 0, 0, 0, 0
|
self.m_lr, self.m_fb, self.m_ud, self.m_yv = 0, 0, 0, 0
|
||||||
|
|
||||||
if self.is_manual and not self.emergency_stop:
|
if self.is_manual and not self.emergency_stop:
|
||||||
s = 100 # Maximum manual speed
|
s = 100
|
||||||
if key == ord('w'): self.m_fb = s
|
if key == ord('w'): self.m_fb = s
|
||||||
elif key == ord('s'): self.m_fb = -s
|
elif key == ord('s'): self.m_fb = -s
|
||||||
elif key == ord('a'): self.m_lr = -s
|
elif key == ord('a'): self.m_lr = -s
|
||||||
|
|||||||
1462
models/face_detection_yunet.onnx
Normal file
1462
models/face_detection_yunet.onnx
Normal file
File diff suppressed because one or more lines are too long
BIN
models/midas_small.onnx
Normal file
BIN
models/midas_small.onnx
Normal file
Binary file not shown.
BIN
models/midas_small.onnx.data
Normal file
BIN
models/midas_small.onnx.data
Normal file
Binary file not shown.
BIN
models/mobilenet_v3.onnx
Normal file
BIN
models/mobilenet_v3.onnx
Normal file
Binary file not shown.
BIN
models/mobilenet_v3.onnx.data
Normal file
BIN
models/mobilenet_v3.onnx.data
Normal file
Binary file not shown.
BIN
models/reid_mobilenet.onnx
Normal file
BIN
models/reid_mobilenet.onnx
Normal file
Binary file not shown.
BIN
models/reid_mobilenet.onnx.data
Normal file
BIN
models/reid_mobilenet.onnx.data
Normal file
Binary file not shown.
0
models/yolov8n.onnx
Normal file
0
models/yolov8n.onnx
Normal file
@@ -1,4 +1,10 @@
|
|||||||
ursina==7.0.0
|
ursina==7.0.0
|
||||||
PyOpenGL==3.1.9
|
PyOpenGL==3.1.9
|
||||||
numpy==2.2.3
|
numpy>=2.0.0
|
||||||
opencv-python==4.11.0.86
|
opencv-python>=4.10.0.0
|
||||||
|
opencv-contrib-python>=4.10.0.0
|
||||||
|
djitellopy>=2.5.0
|
||||||
|
onnxruntime>=1.19.0
|
||||||
|
torch>=2.0.0
|
||||||
|
torchvision>=0.15.0
|
||||||
|
Pillow>=10.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user