Skip to content

Robot.py #663

@alzaky

Description

@alzaky

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()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions