** DEPRECATED. Use digirig-openclaw-channel for all this functionality and much more **
W6RGC/AI is a voice-to-LLM bridge for ham radio. It lets operators talk to AI over the air, routing voice to and from a configurable text-based intelligence engine (OpenClaw, Gemini, ChatGPT, or Ollama). Like Siri or Google Assistant, activate using its hotword "Seven", then speak as you would to another operator, like speak "Seven: Send an APRS message to W6RGC."
- Radio-first UX: Wake word detection, PTT management, carrier sense, and periodic ID support.
- Multi-engine LLM routing: OpenClaw, Gemini, ChatGPT, or Ollama.
- Local tool execution:
- OpenClaw: Invoke tools on your machine, subject to policy.
- Voice APRS: Send and receive APRS messages by voice
- Voice-based location services: Describe your location to get a grid square and GPS.
- Wikipedia: Ask for a concise summary of any topic.
- And more. Just ask Seven.
- Multiple Hardware Interfaces: DigiRig and Baofeng All-in-One Connector (AIOC).
- Off grid: Configurable to run completely on local models for all AI operations (main LLM, wake word detection, speech recognition, and text-to-speech)
Voice APRS demonstrates the natural language APRS capabilities of W6RGC/AI, allowing operators to send and receive APRS messages using conversational voice commands.
📺 Watch the Voice APRS Demo Video
Example Voice Commands:
- "Seven, send an APRS message to N0CALL saying hello from the AI assistant"
- "Seven, read my APRS messages"
- "Seven, check if I have any new APRS traffic"
Features:
- Natural language processing for APRS operations
- Automatic message formatting and validation
- Integration with findu.com APRS gateway
- Supports both sending and receiving messages
- Phonetic readback of callsigns and messages
Key modules you can extend:
main.py: Orchestration loopconstants.py: Centralized configurationregex_command_tooling.py: Voice command parsingril_aioc.py/ril_digirig.py: Radio interface layerscontext_manager.py: Prompt + conversation statewake_word_detector.py: AST-based wake word detectionperiodically_identify.py: Periodic station IDaprs_helper.py,arrl_news_helper.py,wikipedia_helper.py,location_helper.py: External data helpersspeech_recognition.py: Whisper speech-to-textllm_gemini.py,llm_ollama.py,llm_openclaw.py: LLM connectors
- CUDA Hardware: For GPU acceleration, this project requires dedicated GPU hardware to run local AI models. A Nvidia GeForce RTX 3060 or better is recommended.
- Audio Hardware with PTT: Digirig and AIOC (All-In-One-Cable) are supported.
- Operating System: This project has only been tested on Linux.
- Required Linux Packages: Install the following packages using your package manager:
sudo apt update sudo apt install python3-full portaudio19-dev ffmpeg
- User Permissions: Add your user to the
dialoutgroup for serial port access:Log out and back in for changes to take effectsudo usermod -a -G dialout $USER - Ollama: Install Ollama by running the following command in your terminal:
After installation, ensure the Ollama service is running and you have pulled a model (e.g.,
curl -fsSL https://ollama.com/install.sh | shollama pull gemma2:9b).
- Clone the repository:
git clone https://github.com/richcannings/w6rgc-ai cd w6rgc-ai - Create a Python virtual environment (recommended):
python3 -m venv venv source venv/bin/activate - Install Python dependencies:
pip install -r requirements.txt
- Add API key files (as needed):
openai_api_key.txtfor ChatGPTgemini_api_key.txtfor Geminiweather_api_key.txtfor weathergoogle_places_api_key.txtfor location servicesopenclaw_api_token.txtfor OpenClaw gateway access
- Set up Ollama (if not done in prerequisites):
- Ensure the Ollama server is running (usually
ollama serveorsystemctl start ollama) - If you haven't already, pull your desired LLM model (e.g.,
ollama pull gemma2:9b)
- Ensure the Ollama server is running (usually
- Hardware Setup:
- Connect your AIOC or Digirig adapter via USB
- The system will automatically detect the audio device and serial port
- Configure the hardware type in
constants.pyby settingDEFAULT_RIL_TYPEto either "aioc" or "digirig"
-
Configure the application:
- Primary Configuration: Edit
constants.pyto modify a few settings:
BOT_CALLSIGNandBOT_PHONETIC_CALLSIGN- If you are using a Digirig, update
DEFAULT_DIGIRIG_SERIAL_PORT. The system automatically detects the correct audio device for both AIOC and Digirig hardware. - Some features may not work until you download the required models (e.g., Piper for TTS) or provide an API key (e.g., for weather reports).
- Explore the file for more settings to tinker with.
- Advanced Configuration: Customize the AI persona and prompts in
context_manager.py. You can also manually set the serial port inconstants.pyif auto-detection fails.
- Primary Configuration: Edit
-
Run the main script:
python main.py
Your radio is the main interface for input and output. The application will start and listen for the configured wake word (default: "Seven"). To interact, say the wake word at the start of your transmission once or twice, followed by your command or query speaking as how you would speak with another operator.
Example: "Seven, what are your commands?", "Seven, start a net. You are Net Control Station.", "Seven, send an APRS message.", or "Seven, what time is it in Eastern?"
To terminate the assistant: "Seven, break" or "Seven, exit" or use Ctrl+C in the terminal.
The system uses MIT's AST (Audio Spectrogram Transformer) model for efficient wake word detection:
- 35+ Available Wake Words: backward, bed, bird, cat, dog, down, eight, five, follow, forward, four, go, happy, house, learn, left, marvin, nine, no, off, on, one, right, seven, sheila, six, stop, three, tree, two, up, visual, wow, yes, zero
- Current Default: "seven"
To change the wake word, modify BOT_NAME and DEFAULT_WAKE_WORD in constants.py to any of the supported words. It's easier for both the user and the AI when BOT_NAME matches the DEFAULT_WAKE_WORD. To change the bot's callsign, update BOT_CALLSIGN, BOT_SPOKEN_CALLSIGN, and BOT_PHONETIC_CALLSIGN in constants.py.
The application uses a centralized configuration system in constants.py. Key sections include:
# LLM Selection
LLM_ENGINE = "openclaw" # Options: gemini, chatgpt, ollama, openclaw
# Ollama Configuration
OLLAMA_URL = "http://localhost:11434/api/generate"
DEFAULT_OFFLINE_MODEL = "gemma2:9b" # Example: "llama3:8b"
# Gemini Configuration
GEMINI_API_KEY_FILE = "gemini_api_key.txt" # Store your Gemini API key in this file
DEFAULT_ONLINE_MODEL = "gemini-3-flash-preview" # Example: "gemini-3-pro-preview"
MAX_RETRIES = 3
RETRY_DELAY = 1.0 # seconds
REQUEST_TIMEOUT = 30 # seconds
# ChatGPT Configuration
OPENAI_API_KEY_FILE = "openai_api_key.txt"
DEFAULT_CHATGPT_MODEL = "gpt-5.2-pro"
# OpenClaw Configuration (local gateway)
OPENCLAW_GATEWAY_URL = "http://localhost:18789"
OPENCLAW_TOKEN_FILE = "openclaw_api_token.txt"
OPENCLAW_AGENT_ID = "main"
# Weather API Configuration (for weather function calling)
WEATHER_API_KEY_FILE = "weather_api_key.txt" # Store your OpenWeatherMap API key here
# Google Places API Configuration
GOOGLE_PLACES_API_KEY_FILE = "google_places_api_key.txt" # Store your Google Places API key here# AST Wake Word Detection
DEFAULT_WAKE_WORD = BOT_NAME # syncing bot name with wake word
AST_CONFIDENCE_THRESHOLD = 0.7
AST_CHUNK_LENGTH_S = 1.0
AST_MODEL_NAME = "MIT/ast-finetuned-speech-commands-v2"
# Wake Word Detection Method
# WAKE_WORD_METHOD_AST = "ast" # This is an internal constant, usually not changed by user
DEFAULT_WAKE_WORD_METHOD = "ast" # Currently "ast" is the primary method
# Command Detection Configuration
MAX_COMMAND_WORDS = 10 # maximum words to check for commands (prevents accidental triggers)# Radio Interface Layer (RIL) Configuration
RIL_TYPE_AIOC = "aioc"
RIL_TYPE_DIGIRIG = "digirig"
DEFAULT_RIL_TYPE = RIL_TYPE_DIGIRIG # Options: "aioc" or "digirig". Change this to switch.
# Serial Port Configuration
DEFAULT_AIOC_SERIAL_PORT = "/dev/ttyACM0" # Serial port for AIOC PTT control
DEFAULT_DIGIRIG_SERIAL_PORT = "/dev/ttyUSB1" # Serial port for Digirig PTT control
SERIAL_TIMEOUT = 1 # seconds
# Carrier Sense Configuration
CARRIER_SENSE_DURATION = 0.5 # seconds to monitor for carrier before PTT
CARRIER_SENSE_MAX_RETRIES = 3 # maximum attempts to find clear frequency
CARRIER_SENSE_RETRY_DELAY = 3.0 # seconds to wait between carrier sense attempts
# Periodic Identification Configuration
PERIODIC_ID_INTERVAL_MINUTES = 10 # minutes between automatic identification announcementsOPERATOR_NAME = "Operator"
BOT_NAME = "seven" # Choose from available wake words, e.g., seven, marvin, sheila, zero, happy, forward.
BOT_CALLSIGN = "W6RGC/AI" # Amateur radio callsign
BOT_SPOKEN_CALLSIGN = "W 6 R G C stroke A I"
BOT_PHONETIC_CALLSIGN = "Whiskey 6 Romeo Golf Charlie Stroke Alpha India"# Script File Path for logging conversation
WRITE_SCRIPT_TO_FILE = False
# TTS Model Options
TTS_MODEL_FAST_PITCH = "tts_models/en/ljspeech/fast_pitch"
TTS_MODEL_SPEEDY_SPEECH = "tts_models/en/ljspeech/speedy_speech"
TTS_MODEL_TACOTRON2 = "tts_models/en/ljspeech/tacotron2-DDC"
# TTS Audio Settings
TTS_INFERENCE_NOISE_SCALE = 0.667
TTS_INFERENCE_NOISE_SCALE_DP = 1.0
TTS_INFERENCE_SIGMA = 1.0
# TTS File Configuration
TTS_OUTPUT_FILE = 'audio/tts_output.wav'Audio Device Not Found:
- Ensure your AIOC or Digirig adapter is connected
- Check
lsusboutput for USB audio device - Verify user is in
dialoutgroup:groups $USER
Serial Port Issues:
- Check available serial ports:
ls /dev/ttyUSB* /dev/ttyACM* - If auto-detection fails, update
DEFAULT_AIOC_SERIAL_PORTorDEFAULT_DIGIRIG_SERIAL_PORTinconstants.py - Verify permissions:
sudo chmod 666 /dev/ttyUSB0(or relevant port)
Wake Word Not Detected:
- Check microphone levels and background noise.
- Adjust
AST_CONFIDENCE_THRESHOLDinconstants.py. - Try a different wake word, such as "marvin," "sheila," "zero," "happy," or "forward."
LLM Connection Issues:
- Ollama: Ensure the service is running:
systemctl status ollama - ChatGPT: Check API key in
openai_api_key.txt - Gemini: Check API key in
gemini_api_key.txt - Models: Verify model availability:
ollama listor test withpython list_gemini_models.py
Weather Service Issues:
- API Key: Ensure valid OpenWeatherMap API key in
weather_api_key.txt - Internet: Weather service requires internet connection
- Test: Run
python weather_helper.pyto test functionality. - API Limits: The free tier has usage limits; check your OpenWeatherMap dashboard.
Enable debug output for wake word detection:
# In wake_word_detector.py, set debug=True when calling listen_for_wake_word
wake_detected = wake_detector.listen_for_wake_word(
audio_device_index=audio_index,
debug=True # Shows prediction scores and confidence levels
)- Minimum: CPU with 4+ cores, 32GB RAM, and 10GB disk space (not including Ollama models)
- GPU with CUDA support: NVIDIA RTX 3060 with 12GB RAM recommended for optimal performance
- Radio interface: Digirig, AIOC (All-In-One-Cable), or other compatible USB audio interface with PTT control
Copyright 2024 Rich Cannings
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

