add models
This commit is contained in:
@@ -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%).*
|
||||||
|
|||||||
@@ -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>
|
||||||
+13
-6
@@ -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)
|
||||||
|
|||||||
+38
-31
@@ -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
|
||||||
|
|||||||
+8
-7
@@ -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
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8
-2
@@ -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