From 7586973e4de5aca67bedb3188701a32414a7e487 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 18 Jan 2026 15:45:12 +0000 Subject: [PATCH] =?UTF-8?q?README.md=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1314 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1314 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ffb796 --- /dev/null +++ b/README.md @@ -0,0 +1,1314 @@ +# 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! 🎉**