1315 lines
36 KiB
Markdown
1315 lines
36 KiB
Markdown
# Raspberry Pi Zero 2W mit Seed Studio ReSpeaker v1.2 - Komplette Anleitung
|
|
## Offline-Sprachsteuerung mit Soundausgabe
|
|
|
|
**Status:** Vollständige Standalone-Konfiguration mit systemctl-Services
|
|
**Zielgruppe:** Anfänger bis Fortgeschrittene
|
|
**Geschrieben:** Januar 2025
|
|
|
|
---
|
|
|
|
## TEIL 1: HARDWARE-VORBEREITUNG UND OS-INSTALLATION
|
|
|
|
### 1.1 Hardware-Anforderungen
|
|
|
|
Du benötigst folgende Komponenten:
|
|
|
|
- **Raspberry Pi Zero 2W** (nicht Zero oder Zero W!)
|
|
- **Seed Studio ReSpeaker Pi Hat v1.2** mit 2 Mikrofonen
|
|
- **microSD-Karte**: mindestens 16GB (Class 10 empfohlen)
|
|
- **USB-Stromversorgung**: 2A Netzteil mit Micro-USB
|
|
- **SD-Kartenleser** zum Flashen auf deinem PC
|
|
- **Computer mit Internetverbindung**
|
|
- *Optional*: HDMI-Monitor, USB-Tastatur/Maus zur Direktverbindung
|
|
|
|
### 1.2 Raspberry Pi OS Installation
|
|
|
|
#### Schritt 1: Raspberry Pi Imager herunterladen
|
|
|
|
1. Öffne [https://www.raspberrypi.com/software/](https://www.raspberrypi.com/software/)
|
|
2. Lade **Raspberry Pi Imager** für dein Betriebssystem herunter
|
|
3. Installiere die Anwendung
|
|
|
|
#### Schritt 2: SD-Karte flashen
|
|
|
|
1. Stecke die microSD-Karte in deinen Kartenleser und verbinde ihn mit dem PC
|
|
2. Öffne Raspberry Pi Imager
|
|
3. Klicke auf **"Gerät auswählen"** und wähle **"Raspberry Pi Zero 2"**
|
|
4. Klicke auf **"Betriebssystem auswählen"** und wähle:
|
|
- **Raspberry Pi OS (Legacy, 32-Bit) - Bullseye**
|
|
- *Hinweis: v1.2 des ReSpeaker-Hats ist am besten mit Bullseye kompatibel*
|
|
5. Klicke auf **"Speicher auswählen"** und wähle deine microSD-Karte
|
|
6. Klicke auf das **Zahnrad-Symbol (Erweiterte Optionen)** und konfiguriere:
|
|
- **Hostname**: `respeaker-pi` (oder ein beliebiger Name)
|
|
- **SSH aktivieren**: Ja (mit Passwort)
|
|
- **Benutzername**: `pi`
|
|
- **Passwort**: Ein sicheres Passwort deiner Wahl (aufschreiben!)
|
|
- **WLAN konfigurieren**:
|
|
- SSID: Dein WiFi-Netzwerk
|
|
- Passwort: Dein WiFi-Passwort
|
|
- Land: `DE` (Deutschland)
|
|
- **Zeitzone**: `Europe/Berlin`
|
|
7. Klicke **"Speichern"** und dann **"Schreiben"**
|
|
8. Warte bis zum Abschluss (5-10 Minuten)
|
|
9. Entnehme die SD-Karte
|
|
|
|
#### Schritt 3: Erster Start
|
|
|
|
1. Stecke die SD-Karte in den **Pi Zero 2W** ein
|
|
2. Verbinde den ReSpeaker Hat mit dem Pi:
|
|
- Ausrichten der GPIO-Pins (40-polige Reihe)
|
|
- ReSpeaker sollte fest aufgesetzt sein
|
|
3. Verbinde die USB-Stromversorgung
|
|
4. Warte 1-2 Minuten für den ersten Start
|
|
|
|
#### Schritt 4: IP-Adresse ermitteln
|
|
|
|
Methode A (über Router):
|
|
1. Öffne die Verwaltungsoberfläche deines WLAN-Routers
|
|
2. Suche nach verbundenen Geräten
|
|
3. Notiere die IP-Adresse von `respeaker-pi`
|
|
|
|
Methode B (mit arp-scan auf Linux/Mac):
|
|
```bash
|
|
sudo arp-scan -l | grep -i "raspberry\|b8:27"
|
|
```
|
|
|
|
Methode C (mit Advanced IP Scanner auf Windows):
|
|
1. Lade [Advanced IP Scanner](https://www.advanced-ip-scanner.com/) herunter
|
|
2. Scanne dein Netzwerk
|
|
3. Suche nach `respeaker-pi`
|
|
|
|
Beispiel-IP: `192.168.1.100`
|
|
|
|
---
|
|
|
|
## TEIL 2: RASPBERRY PI KONFIGURATION
|
|
|
|
### 2.1 SSH-Verbindung herstellen
|
|
|
|
Auf Linux/Mac (Terminal):
|
|
```bash
|
|
ssh pi@192.168.1.100
|
|
# Gib dein Passwort ein
|
|
```
|
|
|
|
Auf Windows: Nutze PuTTY
|
|
1. Lade [PuTTY](https://www.putty.org/) herunter
|
|
2. Öffne PuTTY
|
|
3. Host: `192.168.1.100`
|
|
4. Port: `22`
|
|
5. Klicke "Open"
|
|
6. Login: `pi`
|
|
7. Passwort: (dein gesetztes Passwort)
|
|
|
|
### 2.2 System aktualisieren
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt upgrade -y
|
|
sudo apt install -y git python3-pip python3-dev libatlas-base-dev
|
|
```
|
|
|
|
Dieser Prozess dauert 10-15 Minuten. Warte ab.
|
|
|
|
### 2.3 Audio- und I2C-Konfiguration
|
|
|
|
```bash
|
|
sudo raspi-config
|
|
```
|
|
|
|
Navigiere zu:
|
|
1. **Schnittstellen** → **I2C** → **Aktivieren**
|
|
2. **Schnittstellen** → **SPI** → **Aktivieren**
|
|
3. **Lokalisierungsoptionen** → **Zeitzone** → **Europa** → **Berlin**
|
|
4. **Lokalisierungsoptionen** → **Sprache** → **de_DE.UTF-8**
|
|
5. Bestätige alle Änderungen und **Starten Sie neu**.
|
|
|
|
Nach dem Reboot erneut verbinden:
|
|
```bash
|
|
ssh pi@192.168.1.100
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 3: RESPEAKER HAT INSTALLATION
|
|
|
|
### 3.1 seeed-voicecard Treiber installieren
|
|
|
|
Der ReSpeaker benötigt die speziellen Seeed-Treiber:
|
|
|
|
```bash
|
|
cd ~
|
|
git clone https://github.com/HinTak/seeed-voicecard.git
|
|
cd seeed-voicecard
|
|
sudo ./install.sh
|
|
```
|
|
|
|
Dies dauert 5-10 Minuten. Wenn es fertig ist:
|
|
|
|
```bash
|
|
sudo reboot now
|
|
```
|
|
|
|
Nach dem Reboot wieder verbinden:
|
|
```bash
|
|
ssh pi@192.168.1.100
|
|
```
|
|
|
|
### 3.2 ReSpeaker-Installation verifizieren
|
|
|
|
Überprüfe, ob die Sound-Karte erkannt wurde:
|
|
|
|
```bash
|
|
aplay -l
|
|
```
|
|
|
|
Du solltest folgende Ausgabe sehen:
|
|
```
|
|
**** PLAYBACK hardware devices ****
|
|
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
|
|
card 1: seeed2miccard [seeed-2mic-voicecard], device 0: ...
|
|
```
|
|
|
|
Überprüfe auch die Aufnahmegeräte:
|
|
```bash
|
|
arecord -l
|
|
```
|
|
|
|
Du solltest auch hier `seeed-2mic-voicecard` sehen.
|
|
|
|
### 3.3 Ton-Tests
|
|
|
|
**Lautsprecher testen:**
|
|
```bash
|
|
speaker-test -l 1 -c 2 -t sine -f 1000 -r 48000
|
|
```
|
|
Du solltest einen Ton hören (drücke Ctrl+C zum Beenden).
|
|
|
|
**Mikrofon testen:**
|
|
```bash
|
|
arecord -D hw:1,0 -f S16_LE -c 2 -r 48000 test_recording.wav
|
|
```
|
|
Sprich kurz ins Mikrofon und stoppe mit Ctrl+C. Dann abspielen:
|
|
```bash
|
|
aplay -D hw:1,0 test_recording.wav
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 4: PYTHON-UMGEBUNG EINRICHTEN
|
|
|
|
### 4.1 Notwendige Python-Pakete installieren
|
|
|
|
```bash
|
|
# Audio-Verarbeitung
|
|
sudo apt install -y portaudio19-dev libatlas-base-dev
|
|
pip3 install pyaudio
|
|
|
|
# Spracherkennung
|
|
pip3 install SpeechRecognition
|
|
pip3 install pydub
|
|
|
|
# Offline-Spracherkennung mit Vosk
|
|
pip3 install vosk
|
|
|
|
# Sprachmodell für Deutsch (kleines Modell, ~50MB)
|
|
mkdir -p ~/voice_models
|
|
cd ~/voice_models
|
|
wget https://alphacephei.com/vosk/models/vosk-model-de-0.21.zip
|
|
unzip vosk-model-de-0.21.zip
|
|
rm vosk-model-de-0.21.zip
|
|
```
|
|
|
|
### 4.2 Ordnerstruktur erstellen
|
|
|
|
```bash
|
|
mkdir -p ~/voice_assistant
|
|
mkdir -p ~/voice_assistant/sounds
|
|
mkdir -p ~/voice_assistant/logs
|
|
mkdir -p ~/voice_assistant/config
|
|
cd ~/voice_assistant
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 5: PYTHON-SKRIPTE ERSTELLEN
|
|
|
|
### 5.1 Haupt-Spracherkennungs-Skript
|
|
|
|
Erstelle die Datei `~/voice_assistant/speech_recognizer.py`:
|
|
|
|
```bash
|
|
nano ~/voice_assistant/speech_recognizer.py
|
|
```
|
|
|
|
Kopiere folgenden Code ein:
|
|
|
|
```python
|
|
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Offline-Spracherkennungssystem für Raspberry Pi Zero 2W mit ReSpeaker Hat v1.2
|
|
Funktioniert vollständig offline mit lokalem Vosk-Modell
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import logging
|
|
import queue
|
|
import sounddevice as sd
|
|
import vosk
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
# ============================================================================
|
|
# KONFIGURATION
|
|
# ============================================================================
|
|
|
|
class Config:
|
|
# Pfade
|
|
BASE_DIR = Path(__file__).parent
|
|
MODEL_PATH = Path.home() / "voice_models" / "vosk-model-de-0.21"
|
|
SOUNDS_DIR = BASE_DIR / "sounds"
|
|
LOGS_DIR = BASE_DIR / "logs"
|
|
|
|
# Audio-Einstellungen
|
|
SAMPLERATE = 16000
|
|
BLOCKSIZE = 4096
|
|
DEVICE_INDEX = None # Wird automatisch erkannt
|
|
|
|
# Spracherkennung
|
|
ACTIVATION_WORD = "computer" # Aktivierungswort
|
|
CONFIDENCE_THRESHOLD = 0.5
|
|
LISTENING_TIMEOUT = 10 # Sekunden zum Abhören nach Aktivierungswort
|
|
|
|
# Logging
|
|
LOG_FILE = LOGS_DIR / "voice_assistant.log"
|
|
LOG_LEVEL = logging.INFO
|
|
|
|
# Kommandos und Aktionen
|
|
COMMANDS = {
|
|
"hello": {"sound": "hello.wav", "action": "greet"},
|
|
"musik": {"sound": "music.wav", "action": "play_music"},
|
|
"stopp": {"sound": "stopped.wav", "action": "stop"},
|
|
"zeit": {"sound": "time.wav", "action": "tell_time"},
|
|
"helligkeit": {"sound": "brightness.wav", "action": "adjust_brightness"},
|
|
}
|
|
|
|
# ============================================================================
|
|
# LOGGING-SETUP
|
|
# ============================================================================
|
|
|
|
def setup_logging():
|
|
"""Konfiguriere Logging in Datei und Console"""
|
|
Config.LOGS_DIR.mkdir(exist_ok=True)
|
|
|
|
logger = logging.getLogger("VoiceAssistant")
|
|
logger.setLevel(Config.LOG_LEVEL)
|
|
|
|
# File Handler
|
|
fh = logging.FileHandler(Config.LOG_FILE)
|
|
fh.setLevel(Config.LOG_LEVEL)
|
|
|
|
# Console Handler
|
|
ch = logging.StreamHandler()
|
|
ch.setLevel(Config.LOG_LEVEL)
|
|
|
|
# Formatter
|
|
formatter = logging.Formatter(
|
|
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
)
|
|
fh.setFormatter(formatter)
|
|
ch.setFormatter(formatter)
|
|
|
|
logger.addHandler(fh)
|
|
logger.addHandler(ch)
|
|
|
|
return logger
|
|
|
|
logger = setup_logging()
|
|
|
|
# ============================================================================
|
|
# AUDIO-GERÄTE MANAGEMENT
|
|
# ============================================================================
|
|
|
|
def find_respeaker_device():
|
|
"""
|
|
Suche nach ReSpeaker-Audiogerät und gebe seinen Index zurück
|
|
"""
|
|
logger.info("Suche nach ReSpeaker-Gerät...")
|
|
|
|
try:
|
|
for index, name in enumerate(sd.query_devices()):
|
|
if isinstance(name, dict):
|
|
device_name = name.get('name', '')
|
|
else:
|
|
device_name = str(name)
|
|
|
|
if 'seeed' in device_name.lower():
|
|
logger.info(f"ReSpeaker gefunden: Index {index}, Name: {device_name}")
|
|
return index
|
|
except Exception as e:
|
|
logger.error(f"Fehler bei der Gerätesuche: {e}")
|
|
|
|
logger.warning("ReSpeaker nicht gefunden, nutze Standard-Eingang")
|
|
return None
|
|
|
|
def list_audio_devices():
|
|
"""Zeige alle verfügbaren Audio-Geräte an"""
|
|
logger.info("Verfügbare Audio-Geräte:")
|
|
for index, name in enumerate(sd.query_devices()):
|
|
if isinstance(name, dict):
|
|
device_name = name.get('name', 'Unknown')
|
|
else:
|
|
device_name = str(name)
|
|
logger.info(f" {index}: {device_name}")
|
|
|
|
# ============================================================================
|
|
# SPRACHERKENNUNG
|
|
# ============================================================================
|
|
|
|
class SpeechRecognizer:
|
|
"""
|
|
Offline-Spracherkennung mit Vosk
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""Initialisiere Spracherkenner"""
|
|
logger.info("Initialisiere Spracherkenner...")
|
|
|
|
# Überprüfe ob Modell existiert
|
|
if not Config.MODEL_PATH.exists():
|
|
logger.error(f"Modell nicht gefunden: {Config.MODEL_PATH}")
|
|
logger.error("Bitte installiere das Vosk-Modell (siehe Dokumentation)")
|
|
raise FileNotFoundError(f"Vosk-Modell nicht gefunden: {Config.MODEL_PATH}")
|
|
|
|
# Lade Modell
|
|
try:
|
|
self.model = vosk.Model(str(Config.MODEL_PATH))
|
|
logger.info(f"Vosk-Modell geladen: {Config.MODEL_PATH}")
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Laden des Modells: {e}")
|
|
raise
|
|
|
|
# Suche ReSpeaker-Gerät
|
|
Config.DEVICE_INDEX = find_respeaker_device()
|
|
if Config.DEVICE_INDEX is None:
|
|
list_audio_devices()
|
|
|
|
# Erstelle Audio-Queue
|
|
self.q = queue.Queue()
|
|
self.recognizer = None
|
|
self.stream = None
|
|
self.is_listening = False
|
|
|
|
def audio_callback(self, indata, frames, time, status):
|
|
"""Callback für Audio-Stream"""
|
|
if status:
|
|
logger.warning(f"Audio-Status: {status}")
|
|
self.q.put(bytes(indata))
|
|
|
|
def start_listening(self):
|
|
"""Starte Audio-Stream"""
|
|
logger.info("Starte Audio-Listening...")
|
|
try:
|
|
self.stream = sd.RawInputStream(
|
|
samplerate=Config.SAMPLERATE,
|
|
blocksize=Config.BLOCKSIZE,
|
|
channels=1,
|
|
dtype='int16',
|
|
device=Config.DEVICE_INDEX,
|
|
callback=self.audio_callback
|
|
)
|
|
self.stream.start()
|
|
self.recognizer = vosk.KaldiRecognizer(self.model, Config.SAMPLERATE)
|
|
self.is_listening = True
|
|
logger.info("Audio-Listening aktiv")
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Starten des Audio-Streams: {e}")
|
|
raise
|
|
|
|
def stop_listening(self):
|
|
"""Stoppe Audio-Stream"""
|
|
logger.info("Stoppe Audio-Listening...")
|
|
if self.stream:
|
|
self.stream.stop()
|
|
self.stream.close()
|
|
self.is_listening = False
|
|
|
|
def wait_for_activation(self, timeout=None):
|
|
"""
|
|
Warte auf das Aktivierungswort
|
|
Rückgabe: True wenn erkannt, False bei Timeout
|
|
"""
|
|
logger.info(f"Warte auf Aktivierungswort: '{Config.ACTIVATION_WORD}'")
|
|
|
|
start_time = time.time()
|
|
while True:
|
|
if timeout and (time.time() - start_time) > timeout:
|
|
logger.info("Aktivierungs-Timeout erreicht")
|
|
return False
|
|
|
|
try:
|
|
data = self.q.get(timeout=1)
|
|
except queue.Empty:
|
|
continue
|
|
|
|
if self.recognizer.AcceptWaveform(data):
|
|
result = json.loads(self.recognizer.Result())
|
|
recognized_text = result.get('result', [])
|
|
|
|
if recognized_text:
|
|
text = ' '.join(recognized_text)
|
|
logger.info(f"Erkannt (Aktivierung): {text}")
|
|
|
|
if Config.ACTIVATION_WORD in text.lower():
|
|
logger.info("Aktivierungswort erkannt!")
|
|
return True
|
|
|
|
def listen_for_command(self, timeout=Config.LISTENING_TIMEOUT):
|
|
"""
|
|
Höre auf ein Kommando nach Aktivierung
|
|
Rückgabe: erkannter Text oder None
|
|
"""
|
|
logger.info(f"Höre auf Kommando ({timeout}s)...")
|
|
|
|
self.recognizer = vosk.KaldiRecognizer(self.model, Config.SAMPLERATE)
|
|
start_time = time.time()
|
|
|
|
while True:
|
|
if (time.time() - start_time) > timeout:
|
|
logger.info("Kommando-Timeout")
|
|
return None
|
|
|
|
try:
|
|
data = self.q.get(timeout=1)
|
|
except queue.Empty:
|
|
continue
|
|
|
|
if self.recognizer.AcceptWaveform(data):
|
|
result = json.loads(self.recognizer.Result())
|
|
recognized_text = result.get('result', [])
|
|
|
|
if recognized_text:
|
|
text = ' '.join(recognized_text)
|
|
logger.info(f"Kommando erkannt: {text}")
|
|
return text
|
|
|
|
else:
|
|
# Partial result
|
|
try:
|
|
partial = json.loads(self.recognizer.PartialResult())
|
|
partial_text = partial.get('partial', '')
|
|
if partial_text:
|
|
logger.debug(f"Teilweise: {partial_text}")
|
|
except:
|
|
pass
|
|
|
|
# ============================================================================
|
|
# SOUND-AUSFÜHRUNG
|
|
# ============================================================================
|
|
|
|
class SoundPlayer:
|
|
"""Verwalte Soundausgabe"""
|
|
|
|
def __init__(self):
|
|
self.sounds_dir = Config.SOUNDS_DIR
|
|
self.sounds_dir.mkdir(exist_ok=True)
|
|
|
|
def play_sound(self, filename):
|
|
"""Spiele Sounddatei ab"""
|
|
sound_path = self.sounds_dir / filename
|
|
|
|
if not sound_path.exists():
|
|
logger.warning(f"Sound nicht gefunden: {sound_path}")
|
|
return False
|
|
|
|
try:
|
|
logger.info(f"Spiele Sound ab: {filename}")
|
|
# Nutze aplay zur Ausgabe auf ReSpeaker-Lautsprecher
|
|
subprocess.run(
|
|
['aplay', '-D', 'hw:1,0', str(sound_path)],
|
|
check=True,
|
|
capture_output=True
|
|
)
|
|
logger.info(f"Sound abgespielt: {filename}")
|
|
return True
|
|
except subprocess.CalledProcessError as e:
|
|
logger.error(f"Fehler beim Abspielen von {filename}: {e}")
|
|
return False
|
|
except FileNotFoundError:
|
|
logger.error("aplay nicht gefunden - installiere alsa-utils")
|
|
return False
|
|
|
|
def play_beep(self, frequency=440, duration=0.5):
|
|
"""Spiele einfachen Beep ab"""
|
|
try:
|
|
logger.info(f"Spiele Beep ab ({frequency}Hz, {duration}s)")
|
|
# Generiere Beep mittels sox
|
|
os.system(f'play -n synth {duration} sine {frequency} 2>/dev/null')
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Beep: {e}")
|
|
|
|
# ============================================================================
|
|
# AKTION-HANDLER
|
|
# ============================================================================
|
|
|
|
class ActionHandler:
|
|
"""Behandle erkannte Kommandos und führe Aktionen aus"""
|
|
|
|
def __init__(self, sound_player):
|
|
self.sound_player = sound_player
|
|
|
|
def handle_command(self, recognized_text):
|
|
"""
|
|
Verarbeite erkannten Text und führe entsprechende Aktion aus
|
|
"""
|
|
if not recognized_text:
|
|
logger.warning("Leerer Text erhalten")
|
|
return False
|
|
|
|
text_lower = recognized_text.lower().strip()
|
|
logger.info(f"Verarbeite Kommando: {text_lower}")
|
|
|
|
# Suche nach passendem Kommando
|
|
for command, config in Config.COMMANDS.items():
|
|
if command in text_lower:
|
|
logger.info(f"Kommando erkannt: {command}")
|
|
|
|
# Spiele Sound ab
|
|
if 'sound' in config:
|
|
self.sound_player.play_sound(config['sound'])
|
|
|
|
# Führe Aktion aus
|
|
action = config.get('action')
|
|
if action:
|
|
self.execute_action(action)
|
|
|
|
return True
|
|
|
|
logger.info(f"Kommando nicht in Liste: {text_lower}")
|
|
return False
|
|
|
|
def execute_action(self, action):
|
|
"""Führe spezifische Aktion aus"""
|
|
logger.info(f"Führe Aktion aus: {action}")
|
|
|
|
if action == "greet":
|
|
logger.info("Aktion: Grüßen")
|
|
elif action == "play_music":
|
|
logger.info("Aktion: Musik abspielen")
|
|
elif action == "stop":
|
|
logger.info("Aktion: Stoppen")
|
|
elif action == "tell_time":
|
|
import datetime
|
|
now = datetime.datetime.now().strftime("%H:%M")
|
|
logger.info(f"Aktuelle Zeit: {now}")
|
|
elif action == "adjust_brightness":
|
|
logger.info("Aktion: Helligkeit anpassen")
|
|
|
|
# ============================================================================
|
|
# HAUPT-PROGRAMM
|
|
# ============================================================================
|
|
|
|
class VoiceAssistant:
|
|
"""Haupt-Sprachassistent"""
|
|
|
|
def __init__(self):
|
|
logger.info("=" * 80)
|
|
logger.info("Starte Voice Assistant für Raspberry Pi Zero 2W")
|
|
logger.info("=" * 80)
|
|
|
|
try:
|
|
self.recognizer = SpeechRecognizer()
|
|
self.sound_player = SoundPlayer()
|
|
self.action_handler = ActionHandler(self.sound_player)
|
|
self.running = False
|
|
except Exception as e:
|
|
logger.error(f"Fehler bei der Initialisierung: {e}")
|
|
raise
|
|
|
|
def run(self):
|
|
"""Starte Haupt-Schleife"""
|
|
logger.info("Starte Haupt-Schleife...")
|
|
self.running = True
|
|
|
|
try:
|
|
self.recognizer.start_listening()
|
|
|
|
while self.running:
|
|
try:
|
|
# Warte auf Aktivierungswort
|
|
if self.recognizer.wait_for_activation(timeout=120):
|
|
# Spiele Bestätigungs-Beep
|
|
self.sound_player.play_beep(frequency=1000, duration=0.2)
|
|
|
|
# Höre auf Kommando
|
|
command = self.recognizer.listen_for_command()
|
|
|
|
if command:
|
|
# Verarbeite Kommando
|
|
self.action_handler.handle_command(command)
|
|
else:
|
|
logger.info("Kein Kommando erkannt")
|
|
|
|
except KeyboardInterrupt:
|
|
logger.info("Unterbrochen durch Benutzer")
|
|
break
|
|
except Exception as e:
|
|
logger.error(f"Fehler in Haupt-Schleife: {e}")
|
|
time.sleep(1)
|
|
|
|
finally:
|
|
self.recognizer.stop_listening()
|
|
logger.info("Voice Assistant beendet")
|
|
|
|
def stop(self):
|
|
"""Beende Programm"""
|
|
logger.info("Stoppe Voice Assistant...")
|
|
self.running = False
|
|
|
|
# ============================================================================
|
|
# EINSTIEGSPUNKT
|
|
# ============================================================================
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
assistant = VoiceAssistant()
|
|
assistant.run()
|
|
except KeyboardInterrupt:
|
|
logger.info("Programm beendet")
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
logger.error(f"Kritischer Fehler: {e}", exc_info=True)
|
|
sys.exit(1)
|
|
```
|
|
|
|
Speichere die Datei (Ctrl+X, dann Y, dann Enter).
|
|
|
|
Mache das Skript ausführbar:
|
|
```bash
|
|
chmod +x ~/voice_assistant/speech_recognizer.py
|
|
```
|
|
|
|
### 5.2 Test-Sounddateien erstellen
|
|
|
|
Erstelle einfache Test-Sounds:
|
|
|
|
```bash
|
|
# Test-Sound 1: Hello
|
|
python3 << 'EOF'
|
|
import wave
|
|
import math
|
|
|
|
def generate_tone(frequency, duration, sample_rate=16000):
|
|
"""Generiere einfachen Ton"""
|
|
samples = []
|
|
for i in range(int(sample_rate * duration)):
|
|
sample = int(32767 * 0.3 * math.sin(2 * math.pi * frequency * i / sample_rate))
|
|
samples.append(sample)
|
|
return samples
|
|
|
|
# Erzeuge Ton-Sequenz für "hello"
|
|
sounds = []
|
|
sounds += generate_tone(440, 0.1) # A4
|
|
sounds += generate_tone(494, 0.1) # B4
|
|
sounds += generate_tone(523, 0.2) # C5
|
|
|
|
# Speichere als WAV
|
|
with wave.open('/home/pi/voice_assistant/sounds/hello.wav', 'wb') as f:
|
|
f.setnchannels(1)
|
|
f.setsampwidth(2)
|
|
f.setframerate(16000)
|
|
f.writeframes(b''.join(s.to_bytes(2, byteorder='little', signed=True) for s in sounds))
|
|
|
|
print("hello.wav erstellt")
|
|
EOF
|
|
|
|
# Test-Sound 2: Music start
|
|
python3 << 'EOF'
|
|
import wave
|
|
import math
|
|
|
|
def generate_tone(frequency, duration, sample_rate=16000):
|
|
samples = []
|
|
for i in range(int(sample_rate * duration)):
|
|
sample = int(32767 * 0.3 * math.sin(2 * math.pi * frequency * i / sample_rate))
|
|
samples.append(sample)
|
|
return samples
|
|
|
|
sounds = []
|
|
sounds += generate_tone(523, 0.1) # C5
|
|
sounds += generate_tone(587, 0.1) # D5
|
|
sounds += generate_tone(659, 0.2) # E5
|
|
|
|
with wave.open('/home/pi/voice_assistant/sounds/music.wav', 'wb') as f:
|
|
f.setnchannels(1)
|
|
f.setsampwidth(2)
|
|
f.setframerate(16000)
|
|
f.writeframes(b''.join(s.to_bytes(2, byteorder='little', signed=True) for s in sounds))
|
|
|
|
print("music.wav erstellt")
|
|
EOF
|
|
|
|
# Weitere Sounds analog...
|
|
for sound in stopped time brightness; do
|
|
python3 << EOF
|
|
import wave
|
|
import math
|
|
|
|
def generate_tone(frequency, duration, sample_rate=16000):
|
|
samples = []
|
|
for i in range(int(sample_rate * duration)):
|
|
sample = int(32767 * 0.3 * math.sin(2 * math.pi * frequency * i / sample_rate))
|
|
samples.append(sample)
|
|
return samples
|
|
|
|
sounds = generate_tone(440, 0.3)
|
|
|
|
with wave.open('/home/pi/voice_assistant/sounds/${sound}.wav', 'wb') as f:
|
|
f.setnchannels(1)
|
|
f.setsampwidth(2)
|
|
f.setframerate(16000)
|
|
f.writeframes(b''.join(s.to_bytes(2, byteorder='little', signed=True) for s in sounds))
|
|
|
|
print("${sound}.wav erstellt")
|
|
EOF
|
|
done
|
|
|
|
# Verifiziere Dateien
|
|
ls -la ~/voice_assistant/sounds/
|
|
```
|
|
|
|
### 5.3 Teste das Skript manuell
|
|
|
|
```bash
|
|
cd ~/voice_assistant
|
|
python3 speech_recognizer.py
|
|
```
|
|
|
|
Du solltest folgende Ausgabe sehen:
|
|
```
|
|
2025-01-18 15:30:45 - VoiceAssistant - INFO - ================================================================================
|
|
2025-01-18 15:30:45 - VoiceAssistant - INFO - Starte Voice Assistant für Raspberry Pi Zero 2W
|
|
2025-01-18 15:30:45 - VoiceAssistant - INFO - ================================================================================
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Initialisiere Spracherkenner...
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Vosk-Modell geladen: /home/pi/voice_models/vosk-model-de-0.21
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Suche nach ReSpeaker-Gerät...
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - ReSpeaker gefunden: Index 1, Name: seeed-2mic-voicecard
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Starte Audio-Listening...
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Audio-Listening aktiv
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Haupt-Schleife gestartet
|
|
2025-01-18 15:30:46 - VoiceAssistant - INFO - Warte auf Aktivierungswort: 'computer'
|
|
```
|
|
|
|
**Teste jetzt:**
|
|
1. Sprich: "Computer"
|
|
2. Nach dem Beep sprich: "Musik"
|
|
3. Der Pi sollte `music.wav` abspielen
|
|
|
|
Beende mit **Ctrl+C**.
|
|
|
|
---
|
|
|
|
## TEIL 6: SYSTEMCTL SERVICE ERSTELLEN
|
|
|
|
### 6.1 Service-Datei erstellen
|
|
|
|
Erstelle eine systemctl-Service-Datei, damit der Voice Assistant beim Booten automatisch startet:
|
|
|
|
```bash
|
|
sudo nano /etc/systemd/system/voice-assistant.service
|
|
```
|
|
|
|
Füge folgenden Inhalt ein:
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=Voice Assistant Service for ReSpeaker
|
|
After=network.target sound.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=pi
|
|
WorkingDirectory=/home/pi/voice_assistant
|
|
Environment="PATH=/usr/local/bin:/usr/bin:/bin:/home/pi/.local/bin"
|
|
ExecStart=/usr/bin/python3 /home/pi/voice_assistant/speech_recognizer.py
|
|
Restart=on-failure
|
|
RestartSec=10
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
|
|
# Ressourcen-Limits für Pi Zero
|
|
MemoryMax=256M
|
|
CPUQuota=50%
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
Speichere die Datei (Ctrl+X, Y, Enter).
|
|
|
|
### 6.2 Service aktivieren und starten
|
|
|
|
```bash
|
|
# Lade systemd-Daemon neu
|
|
sudo systemctl daemon-reload
|
|
|
|
# Aktiviere Service für Auto-Start
|
|
sudo systemctl enable voice-assistant.service
|
|
|
|
# Starte Service jetzt
|
|
sudo systemctl start voice-assistant.service
|
|
|
|
# Überprüfe Status
|
|
sudo systemctl status voice-assistant.service
|
|
```
|
|
|
|
### 6.3 Service-Logs anzeigen
|
|
|
|
```bash
|
|
# Zeige aktuelle Logs
|
|
sudo journalctl -u voice-assistant.service -f
|
|
|
|
# Zeige letzte 50 Zeilen
|
|
sudo journalctl -u voice-assistant.service -n 50
|
|
|
|
# Zeige Logs mit Zeitstempel
|
|
sudo journalctl -u voice-assistant.service --since "1 hour ago" -a
|
|
```
|
|
|
|
### 6.4 Service steuern
|
|
|
|
```bash
|
|
# Starte Service
|
|
sudo systemctl start voice-assistant.service
|
|
|
|
# Stoppe Service
|
|
sudo systemctl stop voice-assistant.service
|
|
|
|
# Starte Service neu
|
|
sudo systemctl restart voice-assistant.service
|
|
|
|
# Deaktiviere Auto-Start
|
|
sudo systemctl disable voice-assistant.service
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 7: MONITORING UND LOGGING
|
|
|
|
### 7.1 Log-Rotation einrichten
|
|
|
|
Erstelle Logrotate-Konfiguration um Log-Dateien zu verwalten:
|
|
|
|
```bash
|
|
sudo nano /etc/logrotate.d/voice-assistant
|
|
```
|
|
|
|
Füge ein:
|
|
|
|
```
|
|
/home/pi/voice_assistant/logs/*.log {
|
|
daily
|
|
rotate 7
|
|
compress
|
|
delaycompress
|
|
notifempty
|
|
create 0640 pi pi
|
|
sharedscripts
|
|
}
|
|
```
|
|
|
|
### 7.2 Monitor-Skript erstellen
|
|
|
|
Erstelle `~/voice_assistant/monitor.py` zur Überwachung:
|
|
|
|
```bash
|
|
nano ~/voice_assistant/monitor.py
|
|
```
|
|
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""
|
|
Monitor-Skript zur Überwachung des Voice Assistant Services
|
|
"""
|
|
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from datetime import datetime
|
|
|
|
def check_service_status():
|
|
"""Überprüfe Service-Status"""
|
|
try:
|
|
result = subprocess.run(
|
|
['systemctl', 'status', 'voice-assistant.service'],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
return result.returncode == 0
|
|
except:
|
|
return False
|
|
|
|
def get_recent_logs(lines=10):
|
|
"""Hole letzte Log-Einträge"""
|
|
try:
|
|
result = subprocess.run(
|
|
['sudo', 'journalctl', '-u', 'voice-assistant.service', '-n', str(lines), '-a'],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
return result.stdout
|
|
except:
|
|
return "Logs nicht verfügbar"
|
|
|
|
def restart_service():
|
|
"""Starte Service neu"""
|
|
try:
|
|
subprocess.run(['sudo', 'systemctl', 'restart', 'voice-assistant.service'], check=True)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
def main():
|
|
"""Hauptüberwachung"""
|
|
print("Voice Assistant Monitor")
|
|
print("=" * 60)
|
|
|
|
while True:
|
|
try:
|
|
is_running = check_service_status()
|
|
status = "✓ LÄUFT" if is_running else "✗ GESTOPPT"
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Status: {status}")
|
|
|
|
if not is_running:
|
|
print("Service nicht aktiv, starte neu...")
|
|
if restart_service():
|
|
print("Service neu gestartet")
|
|
time.sleep(5)
|
|
|
|
# Zeige letzte Logs
|
|
print("\nLetzte Log-Einträge:")
|
|
print("-" * 60)
|
|
logs = get_recent_logs(5)
|
|
print(logs)
|
|
print("-" * 60)
|
|
|
|
time.sleep(30) # Überprüfe alle 30 Sekunden
|
|
|
|
except KeyboardInterrupt:
|
|
print("\nMonitor beendet")
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
print(f"Fehler: {e}")
|
|
time.sleep(5)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
```
|
|
|
|
Speichere und starte:
|
|
```bash
|
|
chmod +x ~/voice_assistant/monitor.py
|
|
python3 ~/voice_assistant/monitor.py
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 8: ADVANCED - EIGENE KOMMANDOS HINZUFÜGEN
|
|
|
|
### 8.1 Neue Kommandos definieren
|
|
|
|
Bearbeite die `COMMANDS` Sektion in `speech_recognizer.py`:
|
|
|
|
```python
|
|
COMMANDS = {
|
|
"hello": {"sound": "hello.wav", "action": "greet"},
|
|
"musik": {"sound": "music.wav", "action": "play_music"},
|
|
"stopp": {"sound": "stopped.wav", "action": "stop"},
|
|
"zeit": {"sound": "time.wav", "action": "tell_time"},
|
|
"helligkeit": {"sound": "brightness.wav", "action": "adjust_brightness"},
|
|
# NEU: Eigene Kommandos hinzufügen
|
|
"licht": {"sound": "light.wav", "action": "toggle_light"},
|
|
"temperatur": {"sound": "temp.wav", "action": "read_temp"},
|
|
}
|
|
```
|
|
|
|
### 8.2 Eigene Aktionen implementieren
|
|
|
|
Bearbeite die `execute_action()` Methode in der `ActionHandler` Klasse:
|
|
|
|
```python
|
|
def execute_action(self, action):
|
|
"""Führe spezifische Aktion aus"""
|
|
logger.info(f"Führe Aktion aus: {action}")
|
|
|
|
if action == "greet":
|
|
logger.info("Aktion: Grüßen")
|
|
elif action == "toggle_light":
|
|
logger.info("Aktion: Licht umschalten")
|
|
# Beispiel: GPIO-Pin steuern
|
|
import RPi.GPIO as GPIO
|
|
GPIO.setmode(GPIO.BCM)
|
|
GPIO.setup(17, GPIO.OUT)
|
|
GPIO.output(17, not GPIO.input(17)) # Toggle
|
|
elif action == "read_temp":
|
|
logger.info("Aktion: Temperatur auslesen")
|
|
# Beispiel mit Sensor
|
|
try:
|
|
with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
|
|
temp = float(f.read()) / 1000
|
|
logger.info(f"Aktuelle Temperatur: {temp:.1f}°C")
|
|
except:
|
|
logger.error("Temperatur-Sensor nicht verfügbar")
|
|
```
|
|
|
|
### 8.3 GPIO-Steuerung erweitern
|
|
|
|
Für komplexere GPIO-Anwendungen:
|
|
|
|
```bash
|
|
pip3 install gpiozero
|
|
```
|
|
|
|
Beispiel in `ActionHandler`:
|
|
|
|
```python
|
|
from gpiozero import LED, Motor, Buzzer
|
|
from gpiozero.pins.rpigpio import RPiGPIOFactory
|
|
|
|
class ActionHandler:
|
|
def __init__(self, sound_player):
|
|
self.sound_player = sound_player
|
|
|
|
# Definiere GPIO-Geräte
|
|
# Pin 17: LED
|
|
# Pin 27: Buzzer
|
|
# Pin 22, 23: Motor (Richtung)
|
|
# Pin 24: PWM für Motor-Geschwindigkeit
|
|
try:
|
|
GPIO.setmode(GPIO.BCM)
|
|
self.led = LED(17)
|
|
self.buzzer = Buzzer(27)
|
|
except:
|
|
logger.warning("GPIO-Geräte nicht verfügbar")
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 9: TROUBLESHOOTING
|
|
|
|
### 9.1 Häufige Probleme und Lösungen
|
|
|
|
#### Problem: "ReSpeaker-Gerät nicht gefunden"
|
|
|
|
```bash
|
|
# Überprüfe Geräte
|
|
aplay -l
|
|
arecord -l
|
|
|
|
# Überprüfe I2C-Verbindung
|
|
i2cdetect -y 1
|
|
|
|
# Reboot
|
|
sudo reboot now
|
|
```
|
|
|
|
#### Problem: "Vosk-Modell nicht gefunden"
|
|
|
|
```bash
|
|
# Überprüfe Modell-Pfad
|
|
ls -la ~/voice_models/
|
|
|
|
# Download neu
|
|
mkdir -p ~/voice_models
|
|
cd ~/voice_models
|
|
wget https://alphacephei.com/vosk/models/vosk-model-de-0.21.zip
|
|
unzip vosk-model-de-0.21.zip
|
|
```
|
|
|
|
#### Problem: "Audio sehr leise oder verrauscht"
|
|
|
|
```bash
|
|
# Überprüfe Lautstärke
|
|
alsamixer
|
|
|
|
# Nutze Pfeiltasten zur Anpassung
|
|
# Mit F6 ReSpeaker-Gerät auswählen
|
|
# ESC zum Beenden
|
|
|
|
# Microphone-Gain erhöhen (rechte Pfeiltaste)
|
|
# Playback-Lautstärke erhöhen (linke Pfeiltaste)
|
|
```
|
|
|
|
#### Problem: "Service startet nicht beim Boot"
|
|
|
|
```bash
|
|
# Überprüfe Service
|
|
sudo systemctl status voice-assistant.service
|
|
|
|
# Zeige Fehler
|
|
sudo journalctl -u voice-assistant.service -n 50
|
|
|
|
# Überprüfe Pfade in Service-Datei
|
|
cat /etc/systemd/system/voice-assistant.service
|
|
```
|
|
|
|
#### Problem: "SSH-Verbindung möglich, aber Service antwortet nicht"
|
|
|
|
```bash
|
|
# Überprüfe Netzwerk
|
|
ping 8.8.8.8
|
|
|
|
# Überprüfe SSH-Key
|
|
ssh -vvv pi@192.168.1.100
|
|
|
|
# Starte Pi neu
|
|
sudo reboot now
|
|
```
|
|
|
|
### 9.2 Debug-Modus aktivieren
|
|
|
|
Ändere in `speech_recognizer.py`:
|
|
|
|
```python
|
|
# KONFIGURATION
|
|
class Config:
|
|
# ...
|
|
LOG_LEVEL = logging.DEBUG # Vorher: logging.INFO
|
|
```
|
|
|
|
Starte das Skript mit ausführlichem Logging:
|
|
|
|
```bash
|
|
python3 ~/voice_assistant/speech_recognizer.py 2>&1 | tee ~/voice_assistant/logs/debug.log
|
|
```
|
|
|
|
---
|
|
|
|
## TEIL 10: OPTIMIERUNGEN FÜR PI ZERO 2W
|
|
|
|
### 10.1 Speicher-Optimierung
|
|
|
|
Der Pi Zero 2W hat nur 512MB RAM. Optimierungen:
|
|
|
|
```bash
|
|
# Deaktiviere unnötige Services
|
|
sudo systemctl disable bluetooth.service
|
|
sudo systemctl disable hciuart.service
|
|
sudo systemctl disable avahi-daemon.service
|
|
sudo systemctl disable cups.service
|
|
|
|
# Reduziere GPU-Memory
|
|
sudo nano /boot/config.txt
|
|
```
|
|
|
|
Finde oder erstelle diese Zeile:
|
|
```
|
|
gpu_mem=64
|
|
```
|
|
|
|
Dies reduziert GPU auf 64MB, gibt dem CPU mehr RAM.
|
|
|
|
### 10.2 CPU-Auslastung überwachen
|
|
|
|
```bash
|
|
# Echtzeit-Überwachung
|
|
top
|
|
|
|
# Prozessüberwachung
|
|
ps aux | grep python3
|
|
|
|
# Speichernutzung
|
|
free -h
|
|
|
|
# Disk-Space
|
|
df -h
|
|
```
|
|
|
|
### 10.3 Performance-Tuning
|
|
|
|
Erweitere `Config` in `speech_recognizer.py`:
|
|
|
|
```python
|
|
class Config:
|
|
# ...
|
|
# Optimiert für Pi Zero 2W
|
|
BLOCKSIZE = 8192 # Größere Blöcke für weniger Overhead
|
|
CONFIDENCE_THRESHOLD = 0.4 # Etwas niedriger für schnellere Reaktion
|
|
|
|
# Nutze nur 1 Kern für Vosk
|
|
VOSK_THREADS = 1
|
|
```
|
|
|
|
---
|
|
|
|
## CHECKLISTE FÜR ERFOLGREICHE INSTALLATION
|
|
|
|
- [ ] Pi Zero 2W mit Raspberry Pi OS (Bullseye 32-bit) installiert
|
|
- [ ] ReSpeaker Hat v1.2 korrekt angebracht und verbunden
|
|
- [ ] seeed-voicecard Treiber installiert
|
|
- [ ] I2C und SPI aktiviert
|
|
- [ ] Vosk-Modell (Deutsch) heruntergeladen
|
|
- [ ] Alle Python-Pakete installiert
|
|
- [ ] `speech_recognizer.py` manuell getestet
|
|
- [ ] Sound-Dateien erstellt
|
|
- [ ] systemctl-Service erstellt und aktiviert
|
|
- [ ] Service-Logs überprüft
|
|
- [ ] Aktivierungswort reagiert und Sounds abspielen
|
|
|
|
---
|
|
|
|
## NÄCHSTE SCHRITTE
|
|
|
|
1. **Web-Interface:** Erstelle ein Web-Dashboard zur Verwaltung
|
|
2. **Datenbank:** Speichere Kommandos und Logs in SQLite
|
|
3. **Integration:** Verbinde mit MQTT für Smart Home
|
|
4. **Machine Learning:** Trainiere eigene Sprachmodelle
|
|
5. **Mehrsprachigkeit:** Unterstütze zusätzliche Sprachen
|
|
|
|
---
|
|
|
|
## RESSOURCEN UND REFERENZEN
|
|
|
|
- [Raspberry Pi Dokumentation](https://www.raspberrypi.com/documentation/)
|
|
- [Seeed Studio ReSpeaker Wiki](https://wiki.seeedstudio.com/)
|
|
- [Vosk Offline Speech Recognition](https://alphacephei.com/vosk/)
|
|
- [SpeechRecognition Library](https://github.com/Uberi/speech_recognition)
|
|
- [ALSA Audio Tutorial](https://www.alsa-project.org/)
|
|
|
|
---
|
|
|
|
## HÄUFIG GESTELLTE FRAGEN
|
|
|
|
**F: Kann ich das System auch mit größeren Raspberry Pi Modellen nutzen?**
|
|
A: Ja, das System funktioniert auch mit Pi 3, 4 und 5. Allerdings benötigt der Pi 4/5 mehr Kühlungsvorkehrungen.
|
|
|
|
**F: Wird eine Internetverbindung benötigt?**
|
|
A: Nach der initialen Einrichtung nicht! Das System funktioniert vollständig offline mit Vosk.
|
|
|
|
**F: Kann ich weitere Sprachmodelle nutzen?**
|
|
A: Ja, Vosk bietet Modelle in vielen Sprachen. Lade sie herunter und passe den Modell-Pfad an.
|
|
|
|
**F: Wie erkenne ich, ob der Service läuft?**
|
|
A: Mit `sudo systemctl status voice-assistant.service` oder überprüfe die LEDs auf dem ReSpeaker.
|
|
|
|
---
|
|
|
|
## SUPPORT UND KONTAKT
|
|
|
|
Bei Problemen:
|
|
1. Überprüfe die Logs: `sudo journalctl -u voice-assistant.service`
|
|
2. Konsultiere das Troubleshooting-Kapitel
|
|
3. Öffne ein Issue im GitHub-Repository
|
|
4. Kontaktiere Seeed Studio Support
|
|
|
|
---
|
|
|
|
**Fertig! Dein Pi Zero 2W mit ReSpeaker sollte nun vollständig funktionsfähig sein! 🎉**
|