Join our FREE personalized newsletter for news, trends, and insights that matter to everyone in America

Newsletter
New

Blog Post: Ai Voice Mood Lighting System

Card image cap

Hello everyone. My Project14 project is called “AI Voice Mood Lighting System.” The basic idea is simple: I speak a word → the system recognizes it → the word is mapped to an emotion or situation → the RDK X5 changes an RGB LED to the corresponding color. For example: Danger → Red Freshness → Green Peaceful → Blue Happiness → Yellow Sweetness → Cyan Honesty → White ⚪ Royalty → Magenta Funny → Color-changing dance mode Sleep → Light OFF This project interesting due to the speech-recognition part works offline using Vosk , while the RDK X5 handles the physical RGB LED. What Inspired Me? I wanted to build something that could demonstrate how a person can interact naturally with an embedded system. Instead of pressing a button or typing a command, I wanted to use voice . The idea developed from a simple question: Can I use voice recognition to control a physical RGB LED using the RDK X5? I also wanted the project to work without depending on the internet. That led me to combine: Voice + Offline AI + Embedded Hardware + RGB Visualization. The RGB LED gives an immediate visual response. For example, if I say: “Danger” the system recognizes the keyword and the RDK X5 changes the LED to red . If I say: “Peaceful” the LED changes to blue . This makes the project easy to demonstrate and understand. Project Architecture The project has two major parts. PC side The PC is responsible for: Capturing microphone audio Running the Vosk offline speech-recognition model Converting speech into text Detecting important keywords Mapping keywords to colors Sending HTTP commands to the RDK X5 Providing voice feedback through the PC speaker RDK X5 side The RDK X5 is responsible for: Running the Flask server Receiving HTTP commands Controlling GPIO pins Driving the RGB LED The complete architecture is: HUMAN VOICE │ ▼ PC MICROPHONE │ ▼ VOSK OFFLINE MODEL Speech Recognition │ ▼ KEYWORD DETECTION │ ┌──────────┼──────────┐ │ │ │ Danger Peaceful Happiness │ │ │ RED BLUE YELLOW │ │ │ └──────────┼──────────┘ ▼ HTTP REQUEST │ ▼ RDK X5 FLASK SERVER │ ▼ GPIO PINS │ ▼ RGB LED Hardware Used The main hardware components are: RDK X5 development kit Common-anode RGB LED Current-limiting resistors Jumper wires PC or laptop Microphone Network connection between the PC and RDK X5 The RGB LED channels are connected as follows: RGB Channel RDK X5 GPIO Red GPIO 31 Green GPIO 36 Blue GPIO 37 I used board numbering with: GPIO.setmode(GPIO.BOARD) Each RGB channel is connected through an appropriate current-limiting resistor. Common-Anode RGB LED One important hardware detail in my project is that the RGB LED is common-anode . A common-anode RGB LED has three individual color channels: Red Green Blue By controlling these three channels, I can create several colors. For example: Red + Green = Yellow Green + Blue = Cyan Red + Blue = Magenta Red + Green + Blue = White However, common-anode LEDs use inverted logic. For my setup: GPIO LOW → LED ON GPIO HIGH → LED OFF Therefore, to turn on red: RED → LOW → ON GREEN → HIGH → OFF BLUE → HIGH → OFF This produces red. To make the programming easier, I created a common function that handles this inverted logic. Conceptually: GPIO.LOW if red else GPIO.HIGH This prevents me from having to manually remember the reversed logic for every color. RGB Color System I created functions for the different colors. The logical mapping is: DANGER → RED FRESHNESS → GREEN PEACEFUL → BLUE HAPPINESS → YELLOW SWEETNESS → CYAN HONESTY → WHITE ROYALTY → MAGENTA SLEEP → OFF FUNNY → COLOR CHANGING This gives the RGB LED the role of a simple visual emotion and situation indicator . Bill of Materials (BOM) — Offline Voice-Controlled Emotion RGB Assistant S.No. Component Specification / Purpose Qty. 1 RDK X5 Development Kit Main embedded controller, Flask server & GPIO control 1 2 Common-Anode RGB LED Displays different emotion/status colors 1 3 Resistors Current-limiting resistors for RGB LED channels 3 4 Jumper Wires GPIO and power connections 6–10 5 Breadboard Prototype circuit assembly 1 6 PC / Laptop Offline voice recognition and command processing 1 7 Microphone Captures voice commands 1 8 Network Connection PC ↔ RDK X5 communication using HTTP 1 9 USB Cable / Power Supply Power and/or connection for RDK X5 1 10 RDK X5 compatible power supply Provides power to the development kit 1 Software / AI Components S.No. Software Purpose 1 Python Main programming language 2 Vosk Offline speech recognition 3 vosk-model-small-en-in-0.4 English-India offline speech model 4 Sounddevice Microphone audio capture 5 Flask HTTP server running on RDK X5 6 Requests PC-to-RDK X5 HTTP communication 7 RPi.GPIO / compatible GPIO library RGB LED GPIO control First Development Stage – Testing the LED I did not start by connecting everything together. Instead, I developed the project in stages. First, I tested the RGB LED independently. I tested: OFF ↓ RED ↓ GREEN ↓ BLUE ↓ YELLOW ↓ CYAN ↓ MAGENTA ↓ WHITE ↓ OFF This was important because I wanted to confirm that the GPIO connections and common-anode logic were correct before adding networking and voice recognition. Building the RDK X5 LED Server After confirming that the LED worked, I created a Python Flask server on the RDK X5. from flask import Flask, request import Hobot.GPIO as GPIO import time import atexit # ===================================== # FLASK SERVER # ===================================== app = Flask(__name__) # ===================================== # GPIO SETTINGS # ===================================== RED = 31 GREEN = 36 BLUE = 37 GPIO.setmode(GPIO.BOARD) GPIO.setup( RED, GPIO.OUT ) GPIO.setup( GREEN, GPIO.OUT ) GPIO.setup( BLUE, GPIO.OUT ) # ===================================== # COMMON ANODE RGB LED # LOW = ON # HIGH = OFF # ===================================== def led_off(): GPIO.output(RED, GPIO.HIGH) GPIO.output(GREEN, GPIO.HIGH) GPIO.output(BLUE, GPIO.HIGH) def set_color(red, green, blue): GPIO.output( RED, GPIO.LOW if red else GPIO.HIGH ) GPIO.output( GREEN, GPIO.LOW if green else GPIO.HIGH ) GPIO.output( BLUE, GPIO.LOW if blue else GPIO.HIGH ) # ===================================== # COLORS # ===================================== def red(): set_color(1,0,0) def green(): set_color(0,1,0) def blue(): set_color(0,0,1) def yellow(): set_color(1,1,0) def cyan(): set_color(0,1,1) def magenta(): set_color(1,0,1) def white(): set_color(1,1,1) # ===================================== # COMMAND HANDLER # ===================================== def control_led(color): color = color.lower() if color == "red": red() elif color == "green": green() elif color == "blue": blue() elif color == "yellow": yellow() elif color == "cyan": cyan() elif color == "magenta": magenta() elif color == "white": white() elif color == "off": led_off() else: return False return True # ===================================== # API ROUTES # ===================================== @app.route("/led") def led_control(): try: color = request.args.get( "color" ) if color is None: return "Missing color",400 print( "Received:", color ) result = control_led( color ) if result: return "OK" else: return "Invalid color" except Exception as e: print( "LED ERROR:", e ) return "ERROR" @app.route("/status") def status(): return "RDK RGB SERVER OK" # ===================================== # CLEAN EXIT # ===================================== def cleanup(): print( "GPIO cleanup" ) led_off() GPIO.cleanup() atexit.register( cleanup ) # ===================================== # START # ===================================== led_off() print("==============================") print("RDK X5 RGB LED SERVER READY") print("==============================") app.run( host="0.0.0.0", port=5000, threaded=True ) The server is called: led_server.py, It listens on: Port 5000, The main endpoint is: /led, The color is provided as a URL parameter. For example: /led?color=red , The RDK X5 receives the request and controls the GPIO pins accordingly. I also created a: /status endpoint. This allows me to check whether the LED server is running. The server is configured to accept network connections so that the PC can communicate with the RDK X5. Testing Network Communication Before adding voice recognition, I tested the network communication separately. The process was: PC │ │ HTTP command ▼ RDK X5 Flask Server │ ▼ GPIO │ ▼ RGB LED For example, the PC can request: color=red The RDK X5 receives it and turns the LED red. I repeated this process for the other colors. This staged development helped me identify problems more easily. Adding Offline Voice Recognition Once the hardware and network control were working, I added voice recognition. For this, I used the Vosk offline speech-recognition engine . The model I used is: vosk-model-small-en-in-0.4. The PC microphone captures the audio using Python's sound device library. The audio configuration is: Sample rate: 16000 Hz Channels: 1 Format: int16 The audio is placed into a queue and processed by Vosk. Vosk returns recognized text, which my Python program then analyzes. The important point is that the basic speech-recognition process happens locally , rather than sending my voice to a cloud speech-recognition service. Keyword Detection The system does not need to understand an entire conversation. It mainly needs to identify important keywords. For example: “happiness” ↓ yellow ↓ HTTP request ↓ RDK X5 ↓ RGB = Yellow Similarly: “peaceful” ↓ blue ↓ RDK X5 ↓ RGB = Blue I convert the recognized text to lowercase and then check for keywords. I also added variations to make the system more tolerant. For example: happy / happiness peace / peaceful fresh / freshness danger / dangerous sweet / sweetness honest / honesty royal / royalty This is useful because speech-recognition models do not always return exactly the word that I spoke. START and STOP Control I also added a simple activation mechanism. The system starts in an inactive state: active = False When I say: START the system becomes active. When I say: STOP the system becomes inactive and the LED is turned off. This prevents random conversations or background speech from continuously controlling the LED. It also makes the demonstration more controlled. Funny / Dance Mode I wanted to add something more interesting than just static colors. So I created a special command: FUNNY When I say FUNNY , the LED enters a small dance-light mode. It cycles through: Red Green Blue Yellow Cyan Magenta White The sequence repeats several times with a short delay. Finally, the LED turns off. This gives the project a more interactive and entertaining demonstration. Sleep Command I also added: SLEEP The purpose is simple. When the system recognizes the sleep command: SLEEP ↓ LED OFF This gives me a direct voice command for switching off the visual output. import json import queue import requests import win32com.client import time import os import sounddevice as sd from vosk import Model, KaldiRecognizer # ============================================================ # RDK X5 SETTINGS # ============================================================ RDK_IP = "192.162.6.167" this should change according to your network LED_URL = f"http://{RDK_IP}:5000/led" # ============================================================ # OFFLINE VOSK MODEL # ============================================================ MODEL_PATH = os.path.join( os.path.dirname(__file__), "vosk-model-small-en-in-0.4" ) print() print("======================================") print("Loading offline speech recognition...") print("======================================") print() if not os.path.exists(MODEL_PATH): print("ERROR: Vosk model not found.") print() print("Expected model folder:") print(MODEL_PATH) print() input("Press Enter to exit...") exit() model = Model( MODEL_PATH ) recognizer = KaldiRecognizer( model, 16000 ) print( "Offline speech recognition ready." ) print() # ============================================================ # LAPTOP SPEAKER # ============================================================ speaker = win32com.client.Dispatch( "SAPI.SpVoice" ) speaker.Rate = -1 speaker.Volume = 100 def speak(text): print( "LAPTOP SPEAKER:", text ) speaker.Speak( text ) # ============================================================ # SEND COLOR COMMAND TO RDK # ============================================================ def send_color(color): try: response = requests.get( LED_URL, params={ "color": color }, timeout=3 ) print( "RDK:", response.text ) return True except requests.exceptions.RequestException as e: print() print( "RDK CONNECTION ERROR:" ) print( e ) print() speak( "RDK connection failed" ) return False # ============================================================ # FUNNY / DANCE LIGHTS # ============================================================ def funny_lights(): colors = [ ("red", "Red"), ("green", "Green"), ("blue", "Blue"), ("yellow", "Yellow"), ("cyan", "Cyan"), ("magenta", "Magenta"), ("white", "White") ] print() print( "FUNNY / DANCE LIGHTS STARTED" ) print() # Repeat the color sequence 3 times for repeat in range(3): for color, name in colors: send_color( color ) print( "FUNNY:", name ) time.sleep( 0.5 ) # Turn all lights OFF after dance send_color( "off" ) speak( "Funny dance completed" ) # ============================================================ # MICROPHONE AUDIO QUEUE # ============================================================ audio_queue = queue.Queue() def audio_callback( indata, frames, time_info, status ): if status: print( "AUDIO STATUS:", status ) audio_queue.put( bytes(indata) ) # ============================================================ # SYSTEM STATUS # ============================================================ active = False # ============================================================ # PROCESS VOICE COMMAND # ============================================================ def process_command(command): global active command = command.lower().strip() print() print( "======================================" ) print( "VOSK HEARD:", command ) print( "======================================" ) # ======================================================== # NORMALIZE COMMON SPEECH # ======================================================== command = command.replace( "wake up", "wakeup" ) # ======================================================== # START # ======================================================== if command == "start": active = True speak( "Voice control started" ) print( "SYSTEM STATUS: ACTIVE" ) return # ======================================================== # STOP # ======================================================== if command == "stop": active = False send_color( "off" ) speak( "Voice control stopped" ) print( "SYSTEM STATUS: INACTIVE" ) return # ======================================================== # WAIT FOR START # ======================================================== if active == False: print( "Voice control is OFF." ) print( "Say start to activate." ) return # ======================================================== # DANGER → RED # ======================================================== if ( "danger" in command or "dangerous" in command ): if send_color( "red" ): speak( "Danger. Red color is on" ) return # ======================================================== # FRESHNESS → GREEN # ======================================================== elif ( "freshness" in command or "fresh" in command ): if send_color( "green" ): speak( "Freshness. Green color is on" ) return # ======================================================== # PEACEFUL → BLUE # ======================================================== elif ( "peaceful" in command or "peace" in command ): if send_color( "blue" ): speak( "Peaceful. Blue color is on" ) return # ======================================================== # HAPPINESS → YELLOW # ======================================================== elif ( "happiness" in command or "happy" in command ): if send_color( "yellow" ): speak( "Happiness. Yellow color is on" ) return # ======================================================== # SWEETNESS → CYAN # ======================================================== elif ( "sweetness" in command or "sweet" in command ): if send_color( "cyan" ): speak( "Sweetness. Cyan color is on" ) return # ======================================================== # HONESTY → WHITE # ======================================================== elif ( "honesty" in command or "honest" in command ): if send_color( "white" ): speak( "Honesty. White color is on" ) return # ======================================================== # ROYALTY → MAGENTA # ======================================================== elif ( "royalty" in command or "royal" in command ): if send_color( "magenta" ): speak( "Royalty. Magenta color is on" ) return # ======================================================== # FUNNY → DANCE / ALL COLORS # ======================================================== elif ( "funny" in command or "fun" in command ): speak( "Funny mode started" ) funny_lights() return # ======================================================== # SLEEP → ALL LIGHTS OFF # ======================================================== elif "sleep" in command: if send_color( "off" ): speak( "Sleep. All lights are off" ) return # ======================================================== # EXIT # ======================================================== elif "exit" in command: speak( "Program closed" ) raise KeyboardInterrupt # ======================================================== # UNKNOWN COMMAND # ======================================================== else: print( "Command not recognized:" ) print( command ) speak( "Command not recognized" ) # ============================================================ # PROGRAM START # ============================================================ print() print("======================================") print("RDK X5 OFFLINE EMOTION RGB ASSISTANT") print("======================================") print() print( "RDK IP:", RDK_IP ) print() print( "VOICE COMMANDS" ) print( "-------------------------------" ) print( "START -> Activate system" ) print( "STOP -> Deactivate system" ) print( "DANGER -> Red" ) print( "FRESHNESS -> Green" ) print( "PEACEFUL -> Blue" ) print( "HAPPINESS -> Yellow" ) print( "SWEETNESS -> Cyan" ) print( "HONESTY -> White" ) print( "ROYALTY -> Magenta" ) print( "FUNNY -> Dance all colors" ) print( "SLEEP -> All lights OFF" ) print( "EXIT -> Close program" ) print( "-------------------------------" ) print() speak( "System ready. Say start" ) # ============================================================ # START MICROPHONE # ============================================================ try: with sd.RawInputStream( samplerate=16000, blocksize=8000, dtype="int16", channels=1, callback=audio_callback ): print() print( "======================================" ) print( "MICROPHONE READY" ) print( "======================================" ) print() print( "Say START to activate." ) print( "Say STOP to deactivate." ) print() while True: data = audio_queue.get() if recognizer.AcceptWaveform( data ): result = json.loads( recognizer.Result() ) command = result.get( "text", "" ) if command: process_command( command ) # ============================================================ # KEYBOARD INTERRUPT # ============================================================ except KeyboardInterrupt: print() print( "Program stopped." ) # ============================================================ # PROGRAM ERROR # ============================================================ except Exception as e: print() print( "PROGRAM ERROR:" ) print( e ) print() # ============================================================ # CLEANUP # ============================================================ finally: try: send_color( "off" ) except Exception: pass print() print( "Voice control closed." ) print() PC-to-RDK X5 Communication The PC communicates with the RDK X5 using HTTP. The Python program sends a request similar to: requests.get( LED_URL, params={"color": color}, timeout=3 ) The important advantage of this design is that the PC does not directly control the RDK X5 GPIO. Instead: PC │ │ HTTP ▼ Flask API │ ▼ GPIO │ ▼ RGB LED This creates a clean separation between the software and hardware. I also added timeout and exception handling so that if the RDK X5 cannot be reached, the PC program can report the connection problem instead of simply crashing. A Major First Challenge – Offline Speech Recognition The biggest challenge I faced was offline keyword recognition accuracy . Initially, I expected the offline model to recognize my keywords consistently. But during testing, I discovered that some words were not recognized correctly every time. The result could be affected by: Pronunciation Microphone quality Background noise Speaking distance Speaking volume The vocabulary of the model For example, I might speak a keyword correctly, but Vosk could sometimes return a different word. That becomes a problem because my application needs to detect a specific keyword before it can select a color. Offline vs Online Recognition During development, I also compared the offline recognition with an online speech-recognition approach. In my testing, the online system performed better for some of my phrases. It could recognize certain words more accurately and consistently. However, I specifically wanted this project to demonstrate offline operation . If I simply replaced Vosk with an online service, I would lose an important part of my project concept. So I treated this as an engineering trade-off: ONLINE RECOGNITION │ ├── Better recognition in my testing └── Requires internet/cloud service OFFLINE VOSK │ ├── Local processing ├── No cloud dependency └── More challenging recognition Instead of hiding this limitation, I used it as a learning opportunity. Improved the Recognition I added multiple variations for some keywords. For example: happy / happiness peace / peaceful fresh / freshness danger / dangerous This means the program does not depend on only one exact form of a word. I also kept the speech-recognition system separate from the LED-control system. That means I can improve the recognition algorithm later without changing the RDK X5 GPIO implementation. Second Challenge – Common-Anode Logic Another challenge was understanding the behavior of the common-anode RGB LED. With a common-cathode LED, the logic is different. But with my common-anode LED: LOW = ON, HIGH = OFF Initially, I had to make sure that my software matched the electrical behavior. I solved this by creating a dedicated set_color() function. This made the rest of the program much easier to understand. Instead of thinking about GPIO levels everywhere, I can simply say: set_color(1,0,0) for red, or: set_color(0,1,1) for cyan. Third Challenge – Network Communication The PC and RDK X5 also need to communicate over the network. The PC sends the HTTP command to the RDK X5. Therefore, both devices need to be reachable on the same network. I used an IP address for the RDK X5 and port 5000 for the Flask server. I also added a timeout to the HTTP request. This taught me that even when individual components work correctly, the complete system can still fail because of communication problems. Final Demonstration For my final demonstration, I will show the complete system. Step 1 Start the RDK X5 Flask LED server. Step 2 Start the PC voice-control program. Step 3 Say: START The system becomes active. Step 4 Say: DANGER The RDK X5 receives the command. The LED becomes: RED Step 5 Say: PEACEFUL The LED changes to: BLUE Step 6 Say: HAPPINESS The LED changes to: YELLOW Step 7 Say: FUNNY The LED starts cycling through multiple colors. Dance Mode Step 8 Say: SLEEP The LED turns off. The complete demonstration is: VOICE ↓ OFFLINE SPEECH RECOGNITION ↓ KEYWORD DETECTION ↓ COLOR SELECTION ↓ HTTP COMMAND ↓ RDK X5 ↓ GPIO ↓ RGB LED Demonstration Video I also created a demonstration video of the project: www.youtube.com/watch Future Improvements The RGB LED is only the first stage of my idea. I would like to develop this prototype into a more useful AI-assisted care and interaction device . 1. Better Offline Recognition I would like to investigate: Better Vosk models Smaller command vocabularies More robust keyword matching Better noise handling Instead of allowing a large vocabulary, I could focus recognition specifically on the commands required by my project. 2. Better Noise Handling I would like to test the system with: Background noise Different microphones Different speaking distances Different speaking volumes Multiple speakers This would help determine how reliable the system is in real-world conditions. 3. Camera-Based Mood Detection A future version could include a camera. The system could combine: Voice + Facial Expression to obtain more information about a person's mood. For example: VOICE + CAMERA ↓ MOOD INFORMATION ↓ AI PROCESSING ↓ APPROPRIATE RESPONSE 4. Motion Sensor I would also like to add a motion sensor. This could help the system understand whether a person is moving or whether unusual activity is occurring. 5. Alerts For a command such as DANGER , a future version could do more than turn the LED red. It could potentially: DANGER ↓ RED LED + ALARM + NOTIFICATION + CAREGIVER ALERT 6. More Visual Effects I could also add: Breathing colors Blinking Smooth color transitions Emergency flashing Rainbow effects Emotion-specific animations This would make the RGB output more expressive. Long-Term Vision long-term goal is to develop the prototype into a small AI-assisted care and interaction device. The future concept could look like this: PERSON │ ┌─────────┴─────────┐ │ │ VOICE CAMERA │ │ └─────────┬─────────┘ │ MOTION SENSOR │ ▼ ┌─────────────┐ │ RDK X5 │ │ AI │ └──────┬──────┘ │ ┌─────────┼─────────┐ ▼ ▼ ▼ RGB ALERT OTHER LED SYSTEM DEVICES │ │ │ └─────────┼─────────┘ ▼ USER / CAREGIVER The device could eventually combine different types of information instead of relying only on one voice keyword. Possible Applications The concept could potentially be useful in areas such as: Children A simple interactive device could provide visual feedback when a child speaks a command. Elder Care Voice commands could provide a simple interface for communicating basic needs or situations. Patient Assistance In a future and more carefully validated version, voice commands could help communicate simple requests or situations when normal communication is difficult. These are future possibilities, not capabilities of my current prototype. What I Learned The most important thing I learned from this project is that building an AI system is not just about making the model work once. There is a big difference between: “The model can recognize speech.” and “The model can reliably recognize the exact commands my application needs.” My testing showed that online speech recognition could be more accurate for some phrases, while the offline model gave me the advantage of local processing and no cloud dependency. This taught me about: Speech-recognition limitations Vocabulary Microphone input Background noise Keyword matching Error handling HTTP communication Flask servers GPIO control RGB electronics System architecture The trade-offs between offline and online AI I also learned the importance of developing a project in stages. First I tested the LED. Then I tested the network. Then I added voice recognition. Finally, I connected everything together. This made it much easier to identify and solve problems. Conclusion My current system demonstrates: Voice → Offline AI → Keyword → HTTP → RDK X5 → GPIO → RGB LED It combines: Python + Vosk + Sounddevice + Flask + HTTP + GPIO + RGB LED The most important part of this project for me was not simply making an LED change color. It was understanding the complete journey from human speech to physical hardware , and learning how to solve the practical problems along the way. The main challenge I am continuing to work on is improving the reliability of offline keyword recognition. In the future, I would like to expand the project from: Voice + RGB LED into: Voice + Camera + Motion → AI Understanding → Useful Action My ultimate goal is to develop this prototype into a more robust, standalone, AI-assisted device that can provide simple and useful interaction for people. Thank you.