.. include:: /index.rst :start-after: start_hello_message :end-before: end_hello_message .. _py_voice_controlled_fan: (Beispiel) Sprachgesteuerter Smart-Ventilator ================================================== **Einführung** Dieses Projekt erstellt einen intelligenten **sprachgesteuerten Smart-Ventilator**, der Spracherkennung, AI-Verarbeitung und Motorsteuerung kombiniert. Das System ermöglicht es Benutzern, die Lüftergeschwindigkeit mit natürlichen Sprachbefehlen zu steuern, und bietet mehrere Steuerungsmethoden: 1. **Sprachbefehle** mithilfe von Speech-to-Text für freihändige Bedienung 2. **Physische Taste** zur manuellen Geschwindigkeitsanpassung 3. **AI-Interpretation** mit OpenAI GPT zum Verstehen natürlicher Sprache 4. **Akustisches Feedback** über einen Buzzer bei Tastendruck 5. **Duale Steueroberfläche** mit Unterstützung für Sprach- und physische Bedienung .. raw:: html Der Smart-Ventilator versteht Befehle wie „mach ihn schneller“, „bitte langsamer“ oder „schalte den Ventilator aus“ und reagiert mit passenden Aktionen sowie einer gesprochenen Bestätigung. Sie können verschiedene Ein- und Ausgabemodule kombinieren, um sprachgesteuerte Smart-Geräte zu erstellen. Siehe: * :ref:`py_online_llm` * :ref:`py_stt_whisper` * :ref:`py_motor` ---------------------------------------------- **Was Sie benötigen** Für dieses Projekt werden die folgenden Komponenten benötigt: .. list-table:: :widths: 30 20 :header-rows: 1 * - COMPONENT - PURCHASE LINK * - :ref:`cpn_motor` - |link_motor_buy| * - :ref:`cpn_button` - |link_button_buy| * - :ref:`cpn_buzzer` - \- * - :ref:`cpn_fusion_hat` - \- * - :ref:`cpn_wires` - |link_wires_buy| * - Raspberry Pi - \- ---------------------------------------------- **Schaltplan** Verbinden Sie die Komponenten wie folgt mit dem Fusion HAT+: .. image:: img/fzz/llm_fan_bb.png :width: 80% :align: center ---------------------------------------------- .. include:: python_online_llms.rst :start-after: start_setup_openai :end-before: end_setup_openai ---------------------------------------------- **Beispiel ausführen** #. Code ausführen .. raw:: html .. code-block:: shell cd ~/ai-lab-kit/llm sudo python3 llm_openai_fan.py #. Den Ventilator steuern Sie können den Ventilator mit Sprachbefehlen, der Taste oder über natürliche Sprache steuern. * Sprachbefehle: - „Mach ihn schneller“ / „Geschwindigkeit erhöhen“ → Setzt die Geschwindigkeit auf maximal (100 %) - „Langsamer“ / „Geschwindigkeit verringern“ → Setzt die Geschwindigkeit auf niedrig (25 %) - „Bitte mittlere Geschwindigkeit“ → Setzt die Geschwindigkeit auf mittel (50 %) - „Ausschalten“ / „Stopp“ → Stoppt den Motor (0 %) - „Wie hoch ist die aktuelle Geschwindigkeit?“ → Gibt die aktuelle Geschwindigkeit aus - „Mach es kühler“ → Wird als Wunsch nach höherer Geschwindigkeit interpretiert * Tastensteuerung: - Jeder Tastendruck erhöht die Geschwindigkeit um 10 % - Bei 100 % springt der nächste Tastendruck wieder auf 0 % - Ein akustisches Signal bestätigt jeden Tastendruck - Die aktuelle Geschwindigkeit in Prozent wird auf dem Bildschirm angezeigt * Verarbeitung natürlicher Sprache: Die AI versteht auch Varianten wie: - „Mir ist heiß, kannst du ihn schneller machen?“ - „Könntest du den Ventilator bitte etwas herunterregeln?“ - „Hier drin ist es zu windig!“ - „Stell ihn auf halbe Geschwindigkeit“ -------- **Code** Hier ist das vollständige Python-Skript für den sprachgesteuerten Smart-Ventilator: .. raw:: html .. code-block:: python from fusion_hat.llm import OpenAI from secret import OPENAI_API_KEY from fusion_hat.motor import Motor from fusion_hat.modules import Buzzer from fusion_hat.pin import Pin import random, time from fusion_hat.stt import STT # Initialize Speech-to-Text with English language stt = STT(language="en-us") # Initialize motor on port M0 motor = Motor('M0') # Initialize button on GPIO 17 with pull-up and debounce button = Pin(17, mode=Pin.IN, pull=Pin.PULL_UP, bounce_time=0.05) # Initialize buzzer on GPIO 4 buzzer = Buzzer(Pin(4)) # Global speed variable (0-100%) speed = 0 # Function for auditory feedback def beep(): buzzer.on() time.sleep(0.1) buzzer.off() # Debounce variables for button last_triggered = 0 # Button callback function def speed_up(): global speed, last_triggered # Debounce: ignore if pressed within 500ms if time.time() - last_triggered < 0.5: return last_triggered = time.time() # Increase speed by 10% speed += 10 # Wrap around at 100% (go back to 0) if speed > 100: motor.stop() speed = 0 else: motor.power(speed) # Auditory feedback beep() # Print current speed print(f"Speed set to: {speed}%") # Attach callback to button button.when_activated = speed_up # Function to parse natural language response and set appropriate speed def parse_response_for_speed(text_response): """ Parse the LLM's natural language response to determine speed setting. Looks for keywords related to different speed levels. Returns the speed level to set (100, 50, 25, or 0) """ text_lower = text_response.lower() # Check for "stop" or "off" keywords - highest priority if any(word in text_lower for word in ['stop', 'off', 'zero', '0%', 'turn off', 'shut off', 'halt']): return 0 # Check for "slow" or "low" keywords if any(word in text_lower for word in ['slow', 'low', '25%', 'quarter', 'minimum', 'gentle']): return 25 # Check for "medium" or "half" keywords if any(word in text_lower for word in ['medium', 'half', '50%', 'moderate', 'normal']): return 50 # Check for "fast" or "high" or "full" keywords if any(word in text_lower for word in ['fast', 'high', 'full', '100%', 'maximum', 'top']): return 100 # If no specific keywords found, return -1 to indicate no speed change return -1 # Setup LLM with specific instructions for fan control INSTRUCTIONS = ''' You are a fan control assistant. Your task is to interpret the user's speech input and respond with natural language. ### Input Format: The user will speak their command for fan control. ### CRITICAL RULES: 1. **BE DECISIVE**: Always take clear action based on user requests. Do NOT ask follow-up questions. 2. **NO CLARIFICATION QUESTIONS**: Never ask "Would you like me to..." or "Should I..." questions. 3. **ASSUME INTENT**: If the user's request is ambiguous, make a reasonable assumption and take action. 4. **CONFIRM ACTION**: Always state what action you are taking in your response. ### Response Guidelines: 1. Respond naturally and conversationally to the user's request. 2. Acknowledge what the user asked for. 3. Use clear language about what action you're taking. 4. Use keywords in your response that indicate speed levels: - For maximum speed: use words like "fast", "high", "full speed", "maximum" - For medium speed: use words like "medium", "half speed", "50%" - For low speed: use words like "slow", "low", "quarter speed", "25%" - For stopping: use words like "stop", "off", "zero", "turning off" 5. If the user asks about current status, respond with helpful information. ### Example Responses: **When asked to go fast:** "I'll set the fan to maximum speed for you. Full speed activated!" **When asked to slow down:** "Reducing the fan speed to low. Enjoy the gentle breeze." **When asked for medium speed:** "Setting the fan to medium speed. This should be comfortable." **When asked to stop:** "Stopping the fan now. The motor is turned off." **When asked about status:** "Your fan is currently at 50% speed. Would you like me to adjust it?" ''' WELCOME = "Hello, I am a fan control assistant. You can ask me to set the fan to fast, medium, slow, or stop it completely. You can also press the button to increase the speed by 10% or decrease it by 10%. If you ask about the current status, I will tell you the current speed. If you don't know what to do, you can ask me for instructions. Good luck!" # Initialize OpenAI LLM llm = OpenAI( api_key=OPENAI_API_KEY, model="gpt-4o", ) # Set how many messages to keep llm.set_max_messages(20) # Set instructions llm.set_instructions(INSTRUCTIONS) # Set welcome message llm.set_welcome(WELCOME) print(WELCOME) # Main loop for voice control while True: print("Say something") # Listen for speech input for result in stt.listen(stream=True): if result["done"]: # Print final recognized text print(f"\r\x1b[Kfinal: {result['final']}") # Get the recognized speech input_text = result['final'] # Add current speed context to the input contextual_input = f"Current speed is {speed}%. User says: {input_text}" # Get response from LLM response = llm.prompt(contextual_input, stream=True) # Collect the full response full_response = "" for next_word in response: if next_word: print(next_word, end="", flush=True) full_response += next_word print("\n") # Add newline after response # Parse the response to determine speed setting new_speed = parse_response_for_speed(full_response) # Apply speed change if detected if new_speed >= 0: speed = new_speed motor.power(speed) print(f"Speed set to: {speed}%") else: print("No speed change detected in response") else: # Print partial recognition results print(f"\r\x1b[Kpartial: {result['partial']}", end="", flush=True) ---------------------------------------------- **Code verstehen** 1. Initialisierung von Speech-to-Text Das System verwendet STT (Speech-to-Text) zur Spracherkennung: .. code-block:: python stt = STT(language="en-us") for result in stt.listen(stream=True): if result["done"]: input_text = result['final'] else: print(f"partial: {result['partial']}") Dadurch wird eine Spracherkennung in Echtzeit mit Teilergebnissen während des Sprechens ermöglicht. 2. Einrichtung der Motorsteuerung Der Lüftermotor wird per PWM über Port M0 gesteuert: .. code-block:: python motor = Motor('M0') # Geschwindigkeit als Prozentwert setzen (0-100) motor.power(speed) # Motor vollständig stoppen motor.stop() 3. Taster mit Entprellung Der Taster verwendet eine Entprellung, um Mehrfachauslösungen zu verhindern: .. code-block:: python button = Pin(17, mode=Pin.IN, pull=Pin.PULL_UP, bounce_time=0.05) last_triggered = 0 def speed_up(): global speed, last_triggered if time.time() - last_triggered < 0.5: # 500 ms Entprellung return last_triggered = time.time() 4. Akustisches Feedback Ein Buzzer gibt eine akustische Bestätigung: .. code-block:: python buzzer = Buzzer(Pin(4)) def beep(): buzzer.on() time.sleep(0.1) buzzer.off() 5. Funktion zum Parsen von Schlüsselwörtern Das System analysiert AI-Antworten auf Geschwindigkeitsbefehle: .. code-block:: python def parse_response_for_speed(text_response): text_lower = text_response.lower() # Auf Schlüsselwörter wie "stop" oder "off" prüfen if any(word in text_lower for word in ['stop', 'off', 'zero']): return 0 # Auf Schlüsselwörter wie "slow" oder "low" prüfen if any(word in text_lower for word in ['slow', 'low', '25%']): return 25 # Ähnliche Prüfungen für medium und fast return -1 # Keine Geschwindigkeitsänderung 6. Kontextbezogene Eingabe an die AI Die aktuelle Geschwindigkeit wird in den Prompt aufgenommen, damit die AI kontextbezogen reagieren kann: .. code-block:: python contextual_input = f"Current speed is {speed}%. User says: {input_text}" response = llm.prompt(contextual_input, stream=True) 7. Verarbeitung gestreamter Antworten AI-Antworten werden Wort für Wort verarbeitet: .. code-block:: python full_response = "" for next_word in response: if next_word: print(next_word, end="", flush=True) full_response += next_word 8. Doppelte Steuerlogik Das System unterstützt sowohl Sprach- als auch Tastensteuerung: .. code-block:: python # Sprachsteuerung in der Hauptschleife new_speed = parse_response_for_speed(full_response) if new_speed >= 0: speed = new_speed motor.power(speed) # Tastensteuerung per Callback def speed_up(): speed += 10 if speed > 100: speed = 0 motor.power(speed) 9. Saubere Terminalausgabe Verwendet ANSI-Escape-Codes für eine übersichtliche Konsolenausgabe: .. code-block:: python print(f"\r\x1b[Kpartial: {result['partial']}", end="", flush=True) - ``\r``: Wagenrücklauf (zum Zeilenanfang springen) - ``\x1b[K``: Vom Cursor bis zum Zeilenende löschen - ``end=""``: Kein Zeilenumbruch - ``flush=True``: Sofortige Ausgabe 10. Intelligente AI-Anweisungen Die AI wird ausdrücklich angewiesen, entschlossen zu handeln und keine Rückfragen zur Klärung zu stellen: .. code-block:: python INSTRUCTIONS = ''' CRITICAL RULES: 1. BE DECISIVE: Always take clear action based on user requests. 2. NO CLARIFICATION QUESTIONS: Never ask "Would you like me to..." questions. 3. ASSUME INTENT: If ambiguous, make reasonable assumption and take action. 4. CONFIRM ACTION: Always state what action you are taking. ''' ---------------------------------------------- **Fehlerbehebung** - Motor dreht sich nicht - Prüfen Sie die Motorverbindungen: M0-Port, richtige Polarität - Testen Sie den Motor direkt: ``motor.power(50)`` sollte ihn mit 50 % drehen lassen - Stellen Sie sicher, dass die Variable ``speed`` korrekt gesetzt wird (Bereich 0-100) - Taster reagiert nicht - Prüfen Sie die Verkabelung: GPIO 17 zum Taster, andere Seite an 3.3V - Überprüfen Sie die Pull-up-Konfiguration - Testen Sie mit einem einfachen Skript: Ausgabe bei jeder Zustandsänderung des Tasters - Prüfen Sie die Entprellzeit (0.5 Sekunden könnten zu lang sein) - Kein Ton vom Buzzer - Testen Sie den Buzzer direkt: ``buzzer.on()`` sollte einen Dauerton erzeugen - Prüfen Sie, ob es sich um einen Piezo-Buzzer (benötigt PWM) oder einen aktiven Buzzer (funktioniert mit Gleichspannung) handelt - AI versteht die Befehle nicht - Prüfen Sie den API-Schlüssel in ``secret.py`` - Überprüfen Sie die Internetverbindung - Kontrollieren Sie die AI-Anweisungen und stellen Sie sicher, dass sie korrekt formatiert sind - Testen Sie zunächst mit einfacheren Befehlen - Geschwindigkeit ändert sich unerwartet - Prüfen Sie die Entprellung des Tasters: möglicherweise wird mehrfach ausgelöst - Überprüfen Sie das Schlüsselwort-Parsing: manche Formulierungen könnten unbeabsichtigt eine bestimmte Geschwindigkeit auslösen - Fügen Sie ``print``-Ausgaben hinzu, um Geschwindigkeitsänderungen nachzuverfolgen - Schlechte Genauigkeit bei der Spracherkennung - Reduzieren Sie Hintergrundgeräusche - Sprechen Sie deutlich und in mäßigem Tempo - Verwenden Sie gegebenenfalls ein externes USB-Mikrofon für bessere Qualität - Passen Sie, falls verfügbar, die STT-Parameter an - Motor macht Geräusche, dreht sich aber nicht - Prüfen Sie, ob der Motor blockiert oder festgeklemmt ist - Stellen Sie sicher, dass die Versorgungsspannung zu den Anforderungen des Motors passt - Manche Motoren benötigen einen Kondensator an den Anschlüssen für einen ruhigeren Lauf ---------------------------------------------- Dieser sprachgesteuerte Ventilator zeigt, wie natürliche Sprachverarbeitung, physische Bedienelemente und intelligente Systeme kombiniert werden können, um intuitive und barrierearme Smart-Home-Geräte zu schaffen, die auf menschliche Bedürfnisse und Vorlieben reagieren.