362 lines
9.8 KiB
Markdown
362 lines
9.8 KiB
Markdown
# Pi Zero 2W + ReSpeaker - OPTIMIERT FÜR 3 KOMMANDOS
|
|
## Lightweight Keyword Spotting statt vollständiges Sprachmodell
|
|
|
|
---
|
|
|
|
## TEIL 1-3: Basis-Installation (wie vorher)
|
|
|
|
Die Schritte zur OS-Installation, SSH-Verbindung und ReSpeaker-Treiber bleiben identisch:
|
|
|
|
1. **Raspberry Pi OS (Bullseye 32-bit) installieren** (TEIL 1)
|
|
2. **SSH-Verbindung + raspi-config** (TEIL 2)
|
|
3. **seeed-voicecard Treiber installieren** (TEIL 3)
|
|
|
|
Folge dazu der ursprünglichen Anleitung bis einschließlich TEIL 3.
|
|
|
|
---
|
|
|
|
## 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. Diese können aus dem Rhasspy-Repo gezogen werden oder als install-respeaker-drivers.sh dieses Verzeichnisses genutzt werden.
|
|
|
|
```bash
|
|
cd ~
|
|
wget 'https://raw.githubusercontent.com/rhasspy/wyoming-satellite/refs/heads/master/etc/install-respeaker-drivers.sh'
|
|
sudo chmod 755 install-respeaker-drivers.sh
|
|
sudo ./install-respeaker-drivers.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
|
|
```
|
|
|
|
---
|
|
|
|
# installieren mit
|
|
pip3 install vosk --break-system-packages
|
|
|
|
mkdir ~/vosk-models
|
|
cd ~/vosk-models
|
|
wget https://alphacephei.com/vosk/models/vosk-model-small-de-0.15.zip
|
|
unzip vosk-model-small-de-0.15.zip
|
|
mv vosk-model-small-de-0.15 model
|
|
|
|
|
|
# aufnehmen mit
|
|
arecord -D plughw:1,0 --format S16_LE --rate 16000 --channels 1 --duration 5 test_mono.wav
|
|
# ausfuehren mit
|
|
python3 test_simple.py test_mono.wav
|
|
|
|
|
|
|
|
|
|
#### test_simple.py
|
|
|
|
```
|
|
#!/usr/bin/env python3
|
|
|
|
import wave
|
|
import sys
|
|
|
|
from vosk import Model, KaldiRecognizer, SetLogLevel
|
|
|
|
# You can set log level to -1 to disable debug messages
|
|
SetLogLevel(0)
|
|
|
|
wf = wave.open(sys.argv[1], "rb")
|
|
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
|
|
print("Audio file must be WAV format mono PCM.")
|
|
sys.exit(1)
|
|
|
|
model = Model("model") #lang="en-us")
|
|
|
|
# You can also init model by name or with a folder path
|
|
# model = Model(model_name="vosk-model-en-us-0.21")
|
|
# model = Model("models/en")
|
|
|
|
rec = KaldiRecognizer(model, wf.getframerate())
|
|
rec.SetWords(True)
|
|
rec.SetPartialWords(True)
|
|
|
|
while True:
|
|
data = wf.readframes(4000)
|
|
if len(data) == 0:
|
|
break
|
|
if rec.AcceptWaveform(data):
|
|
print(rec.Result())
|
|
else:
|
|
print(rec.PartialResult())
|
|
|
|
print(rec.FinalResult())
|
|
```
|
|
|
|
### microphone.py
|
|
```
|
|
#!/usr/bin/env python3
|
|
|
|
# prerequisites: as described in https://alphacephei.com/vosk/install and also python module `sounddevice` (simply run command `pip install sounddevice`)
|
|
# Example usage using Dutch (nl) recognition model: `python test_microphone.py -m nl`
|
|
# For more help run: `python test_microphone.py -h`
|
|
|
|
import argparse
|
|
import queue
|
|
import sys
|
|
import sounddevice as sd
|
|
|
|
from vosk import Model, KaldiRecognizer
|
|
|
|
q = queue.Queue()
|
|
|
|
def int_or_str(text):
|
|
"""Helper function for argument parsing."""
|
|
try:
|
|
|
|
return int(text)
|
|
except ValueError:
|
|
return text
|
|
|
|
def callback(indata, frames, time, status):
|
|
"""This is called (from a separate thread) for each audio block."""
|
|
if status:
|
|
print(status, file=sys.stderr)
|
|
q.put(bytes(indata))
|
|
|
|
parser = argparse.ArgumentParser(add_help=False)
|
|
parser.add_argument(
|
|
"-l", "--list-devices", action="store_true",
|
|
help="show list of audio devices and exit")
|
|
args, remaining = parser.parse_known_args()
|
|
if args.list_devices:
|
|
print(sd.query_devices())
|
|
parser.exit(0)
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
parents=[parser])
|
|
parser.add_argument(
|
|
"-f", "--filename", type=str, metavar="FILENAME",
|
|
help="audio file to store recording to")
|
|
parser.add_argument(
|
|
"-d", "--device", type=int_or_str,
|
|
help="input device (numeric ID or substring)")
|
|
parser.add_argument(
|
|
"-r", "--samplerate", type=int, help="sampling rate")
|
|
parser.add_argument(
|
|
"-m", "--model", type=str, help="language model; e.g. en-us, fr, nl; default is en-us")
|
|
args = parser.parse_args(remaining)
|
|
|
|
try:
|
|
if args.samplerate is None:
|
|
device_info = sd.query_devices(args.device, "input")
|
|
# soundfile expects an int, sounddevice provides a float:
|
|
args.samplerate = int(device_info["default_samplerate"])
|
|
|
|
if args.model is None:
|
|
model = Model(lang="de") #"en-us")
|
|
else:
|
|
model = Model(lang=args.model)
|
|
|
|
if args.filename:
|
|
dump_fn = open(args.filename, "wb")
|
|
else:
|
|
dump_fn = None
|
|
|
|
with sd.RawInputStream(samplerate=args.samplerate, blocksize = 8000, device=args.device,
|
|
dtype="int16", channels=1, callback=callback):
|
|
print("#" * 80)
|
|
print("Press Ctrl+C to stop the recording")
|
|
print("#" * 80)
|
|
|
|
rec = KaldiRecognizer(model, args.samplerate)
|
|
while True:
|
|
data = q.get()
|
|
if rec.AcceptWaveform(data):
|
|
print(rec.Result())
|
|
else:
|
|
partialPrint = rec.PartialResult()
|
|
print(partialPrint)
|
|
if "licht" in partialPrint and "an" in partialPrint and "hex" in partialPrint:
|
|
print("SCHALTER EIN!")
|
|
if "licht" in partialPrint and "aus" in partialPrint and "hex" in partialPrint:
|
|
print("SCHALTER AUS!")
|
|
if dump_fn is not None:
|
|
dump_fn.write(data)
|
|
|
|
except KeyboardInterrupt:
|
|
print("\nDone")
|
|
parser.exit(0)
|
|
except Exception as e:
|
|
parser.exit(type(e).__name__ + ": " + str(e))
|
|
``` |