- Notifications
You must be signed in to change notification settings - Fork 87.3k
Description
import tkinter as tk
import threading
import time
import random
import speech_recognition as sr
from tkinter import ttk
----- Settings -----
OWNER_NAME = "owner"
CONFIRM_TIMEOUT = 5
Enhanced commands with multiple language support
ACTION_MAP = {
"wave": {
"action": "Wave Hand",
"keywords": {
"en": ["wave", "hello", "hi", "greet"],
"ar": ["اهتز", "مرحباً", "لوح", "سلم"]
}
},
"forward": {
"action": "Move Forward",
"keywords": {
"en": ["forward", "front", "ahead", "advance", "go"],
"ar": ["امام", "تقديم", "انطلق", "اسرع"]
}
},
"backward": {
"action": "Move Backward",
"keywords": {
"en": ["backward", "back", "behind", "retreat"],
"ar": ["خلف", "تراجع", "ارجع", "الى وراء"]
}
},
"left": {
"action": "Turn Left",
"keywords": {
"en": ["left", "turn left", "go left"],
"ar": ["يسار", "اتجه يسار", "شمال", "يسارا"]
}
},
"right": {
"action": "Turn Right",
"keywords": {
"en": ["right", "turn right", "go right"],
"ar": ["يمين", "اتجه يمين", "يمينا"]
}
},
"reset": {
"action": "Reset Position",
"keywords": {
"en": ["reset", "home", "center", "stop"],
"ar": ["استعادة", "مركز", "اعد", "توقف"]
}
}
}
ACTIONS = list(ACTION_MAP.keys())
pending = {}
_next_id = 0
lock = threading.Lock()
current_language = "en" # Default language
----- Control Functions -----
def next_id():
global _next_id
with lock:
_next_id += 1
return _next_id
def find_matching_command(text, lang="en"):
"""Find matching command in text with language support"""
text = text.lower().strip()
for cmd_id, cmd_info in ACTION_MAP.items(): # Check keywords in the specified language if lang in cmd_info["keywords"]: for keyword in cmd_info["keywords"][lang]: if keyword.lower() in text: return cmd_id, cmd_info["action"] return None, None def receive_command(from_name, text, confidence=0.8):
"""Receive command with multi-language support"""
# Try current language first
cmd_id, action = find_matching_command(text, current_language)
# If not found, try other languages if not action: for lang in ["en", "ar"]: if lang != current_language: cmd_id, action = find_matching_command(text, lang) if action: break if not action: app.log_event(f"[WARN] Cannot recognize command: {text}") return if from_name == OWNER_NAME and confidence >= 0.55: app.log_event(f"[AUTH] Owner verified → Executing {action}") execute_action(action) return cid = next_id() pending[cid] = {"from": from_name, "action": action, "ts": time.time()} app.update_pending() app.log_event(f"[PENDING-{cid}] {from_name}: {action}. Awaiting confirmation") def wait_timeout(cid):
start = time.time()
while time.time() - start < CONFIRM_TIMEOUT:
time.sleep(0.2)
if cid not in pending:
return
if cid in pending:
info = pending.pop(cid)
app.update_pending()
app.log_event(f"[TIMEOUT] Command {cid} ignored (from {info['from']})")
def confirm_cmd(cid):
if cid in pending:
info = pending.pop(cid)
app.update_pending()
app.log_event(f"[CONFIRMED] Approved {cid} → Executing {info['action']}")
execute_action(info['action'])
else:
app.log_event(f"[CONFIRM] No pending command with id {cid}")
def execute_action(action):
app.log_event(f"[EXECUTE] {action}")
app.perform_action(action)
time.sleep(0.5)
app.log_event(f"[DONE] {action}")
def switch_language(lang):
"""Switch voice recognition language"""
global current_language
current_language = lang
app.log_event(f"[LANGUAGE] Switched to {lang.upper()} voice recognition")
app.update_language_display()
----- Enhanced Voice Recognition -----
def listen_microphone():
r = sr.Recognizer()
try: with sr.Microphone() as source: r.adjust_for_ambient_noise(source, duration=1) app.log_event("[INFO] Ready to listen... Adjusted for ambient noise") except: app.log_event("[WARN] Cannot access microphone") return while True: try: app.log_event(f"[LISTENING] Listening for {current_language.upper()} commands...") with sr.Microphone() as source: r.pause_threshold = 1.0 r.energy_threshold = 300 audio = r.listen(source, timeout=5, phrase_time_limit=3) # Try recognition with current language if current_language == "ar": text = r.recognize_google(audio, language="ar-AR") else: text = r.recognize_google(audio, language="en-US") app.log_event(f"[VOICE] Recognized: '{text}'") if text.strip(): receive_command(OWNER_NAME, text, confidence=0.8) except sr.WaitTimeoutError: continue except sr.UnknownValueError: app.log_event("[ERROR] Could not understand audio") except sr.RequestError as e: app.log_event(f"[ERROR] Recognition service error: {e}") except Exception as e: app.log_event(f"[ERROR] {e}") time.sleep(0.5) ----- Event Simulation -----
def simulate_events():
while True:
time.sleep(random.uniform(5, 8))
who = random.choice(["Alice", "Bob", "Charlie"])
phrase = random.choice(ACTIONS)
conf = 0.55
app.log_event(f"[EVENT] {who} → '{phrase}' (conf={conf:.2f})")
receive_command(who, phrase, conf)
----- Enhanced GUI -----
class RobotApp:
def init(self, master):
self.master = master
master.title("AI Robot Simulator - Multi Language")
master.geometry("850x650")
# Font settings self.title_font = ("Arial", 16, "bold") self.normal_font = ("Arial", 11) self.small_font = ("Arial", 10) # Title Frame title_frame = tk.Frame(master, bg="#2C3E50") title_frame.pack(fill="x", padx=10, pady=5) tk.Label(title_frame, text="AI Robot Simulator - Voice Controlled", font=self.title_font, fg="white", bg="#2C3E50").pack(pady=10) # Language Selection Frame lang_frame = tk.Frame(master) lang_frame.pack(fill="x", padx=10, pady=5) tk.Label(lang_frame, text="Voice Language:", font=self.normal_font).pack(side="left") self.lang_var = tk.StringVar(value="en") tk.Radiobutton(lang_frame, text="English", variable=self.lang_var, value="en", command=lambda: switch_language("en"), font=self.small_font).pack(side="left", padx=10) tk.Radiobutton(lang_frame, text="Arabic", variable=self.lang_var, value="ar", command=lambda: switch_language("ar"), font=self.small_font).pack(side="left", padx=10) # Commands Frame commands_frame = tk.Frame(master, relief="solid", bd=1, padx=10, pady=10) commands_frame.pack(fill="x", padx=10, pady=5) tk.Label(commands_frame, text="Supported Voice Commands:", font=self.normal_font, justify="left").pack(anchor="w") self.commands_display = tk.Text(commands_frame, height=6, wrap="word", font=("Arial", 9)) self.commands_display.pack(fill="x", pady=5) # Robot Canvas self.canvas = tk.Canvas(master, width=500, height=300, bg="white", highlightthickness=1, highlightbackground="#CCCCCC") self.canvas.pack(pady=10) # Manual Control Buttons button_frame = tk.Frame(master) button_frame.pack(pady=10) # Row 1 button_frame1 = tk.Frame(button_frame) button_frame1.pack() buttons1 = [ ("Move Forward", "forward"), ("Move Backward", "backward"), ("Reset Position", "reset") ] for text, action in buttons1: btn = tk.Button(button_frame1, text=text, command=lambda a=action: receive_command(OWNER_NAME, a, 1.0), font=self.small_font, width=15, height=2, bg="#27AE60", fg="white") btn.pack(side="left", padx=5) # Row 2 button_frame2 = tk.Frame(button_frame) button_frame2.pack(pady=5) buttons2 = [ ("Turn Left", "left"), ("Turn Right", "right"), ("Wave Hand", "wave") ] for text, action in buttons2: btn = tk.Button(button_frame2, text=text, command=lambda a=action: receive_command(OWNER_NAME, a, 1.0), font=self.small_font, width=15, height=2, bg="#2980B9", fg="white") btn.pack(side="left", padx=5) # Event Log Frame log_frame = tk.Frame(master) log_frame.pack(fill="both", expand=True, padx=10, pady=5) tk.Label(log_frame, text="Event Log:", font=self.normal_font, justify="left").pack(anchor="w") # Text area with scrollbar text_frame = tk.Frame(log_frame) text_frame.pack(fill="both", expand=True) self.log = tk.Text(text_frame, height=8, wrap="word", font=("Consolas", 9)) scrollbar = tk.Scrollbar(text_frame, command=self.log.yview) self.log.config(yscrollcommand=scrollbar.set) self.log.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y") # Pending Commands Frame pending_frame = tk.Frame(master) pending_frame.pack(fill="x", padx=10, pady=5) tk.Label(pending_frame, text="Pending Commands:", font=self.normal_font, justify="left").pack(anchor="w") self.pending_box = tk.Listbox(pending_frame, height=3, font=self.small_font) self.pending_box.pack(fill="x") # Confirm button confirm_btn = tk.Button(pending_frame, text="Confirm Last Command", command=self.confirm_last, font=self.small_font, bg="#E67E22", fg="white", width=20) confirm_btn.pack(pady=5) self.draw_robot() self.update_sensors() self.update_language_display() def confirm_last(self): if pending: last_cid = list(pending.keys())[-1] confirm_cmd(last_cid) def log_event(self, text): timestamp = time.strftime("%H:%M:%S") formatted_text = f"[{timestamp}] {text}" self.log.insert("end", formatted_text + "\n") self.log.see("end") self.master.update() def update_pending(self): self.pending_box.delete(0, "end") for cid, info in pending.items(): display_text = f"{cid}: {info['from']} → {info['action']}" self.pending_box.insert("end", display_text) def update_language_display(self): """Update the commands display based on current language""" self.commands_display.delete(1.0, "end") lang_name = "English" if current_language == "en" else "Arabic" self.commands_display.insert("end", f"Current Language: {lang_name}\n\n") for cmd_id, cmd_info in ACTION_MAP.items(): if current_language in cmd_info["keywords"]: keywords = ", ".join(cmd_info["keywords"][current_language]) self.commands_display.insert("end", f"• {cmd_info['action']}: {keywords}\n") self.commands_display.config(state="disabled") def draw_robot(self): self.canvas.delete("all") # Robot body self.canvas.create_rectangle(220, 150, 280, 250, fill="#B0BEC5", outline="#37474F", width=2) # Head self.canvas.create_oval(220, 100, 280, 150, fill="#FFEB3B", outline="#37474F", width=2) # Eyes self.canvas.create_oval(235, 115, 245, 125, fill="black") self.canvas.create_oval(255, 115, 265, 125, fill="black") # Arms self.left_arm = self.canvas.create_line(220, 160, 180, 200, width=6, fill="#5D4037") self.right_arm = self.canvas.create_line(280, 160, 320, 200, width=6, fill="#5D4037") # Wheels self.left_wheel = self.canvas.create_oval(210, 250, 230, 270, fill="#212121") self.right_wheel = self.canvas.create_oval(270, 250, 290, 270, fill="#212121") # Sensors self.temp_sensor = self.canvas.create_rectangle(20, 20, 90, 40, fill="#F44336") self.humidity_sensor = self.canvas.create_rectangle(100, 20, 170, 40, fill="#2196F3") # Sensor labels self.canvas.create_text(55, 30, text="Temp", fill="white", font=("Arial", 9, "bold")) self.canvas.create_text(135, 30, text="Humidity", fill="white", font=("Arial", 9, "bold")) def perform_action(self, action): if action == "Wave Hand": for i in range(3): self.canvas.coords(self.right_arm, 280, 160, 340, 140) self.master.update() time.sleep(0.3) self.canvas.coords(self.right_arm, 280, 160, 320, 200) self.master.update() time.sleep(0.3) elif action == "Move Forward": self.canvas.move("all", 0, -20) self.master.update() elif action == "Move Backward": self.canvas.move("all", 0, 20) self.master.update() elif action == "Turn Left": self.canvas.move(self.left_wheel, -15, 0) self.canvas.move(self.right_wheel, -5, 0) self.master.update() elif action == "Turn Right": self.canvas.move(self.left_wheel, 5, 0) self.canvas.move(self.right_wheel, 15, 0) self.master.update() elif action == "Reset Position": self.canvas.delete("all") self.draw_robot() self.master.update() def update_sensors(self): temp = random.randint(20, 35) humidity = random.randint(30, 80) # Update sensor colors temp_color = f"#ff{max(0, 255-temp*7):02x}00" hum_color = f"#0000{min(255, humidity*3):02x}" self.canvas.itemconfig(self.temp_sensor, fill=temp_color) self.canvas.itemconfig(self.humidity_sensor, fill=hum_color) # Update sensor readings self.canvas.delete("sensor_readings") self.canvas.create_text(55, 30, text=f"{temp}°C", fill="white", font=("Arial", 8, "bold"), tags="sensor_readings") self.canvas.create_text(135, 30, text=f"{humidity}%", fill="white", font=("Arial", 8, "bold"), tags="sensor_readings") self.master.after(3000, self.update_sensors) ----- Application Startup -----
if name == "main":
root = tk.Tk()
app = RobotApp(root)
# Start background threads threading.Thread(target=simulate_events, daemon=True).start() threading.Thread(target=listen_microphone, daemon=True).start() app.log_event("✅ Application ready") app.log_event("🎤 Voice commands activated") app.log_event("🔊 You can speak commands in English or Arabic") app.log_event("🌐 Use the radio buttons to switch voice recognition language") root.mainloop()