Spaces:
Runtime error
Runtime error
| # backend/robot_detector.py | |
| import serial.tools.list_ports | |
| import gradio as gr | |
| import json | |
| import os | |
| # Define the path to save/load configurations | |
| CONFIG_FILE = "config/default_config.json" | |
| def list_serial_ports(): | |
| """ | |
| Lista todos los puertos seriales disponibles en el sistema. | |
| """ | |
| ports = serial.tools.list_ports.comports() | |
| port_list = [] | |
| if not ports: | |
| return ["No se encontraron puertos seriales disponibles."] | |
| for port in ports: | |
| port_info = f"{port.device} - {port.description}" | |
| if port.hwid and "VID:PID" in port.hwid: | |
| port_info += f" ({port.hwid})" | |
| port_list.append(port_info) | |
| return port_list | |
| def save_config(follower_port: str, follower_id: str, leader_port: str, leader_id: str): | |
| """ | |
| Guarda la configuraci贸n del robot y teleoperador en un archivo JSON. | |
| """ | |
| config = { | |
| "robot_follower": { | |
| "port": follower_port.split(' ')[0] if follower_port else "", # Extract only device path | |
| "id": follower_id | |
| }, | |
| "teleop_leader": { | |
| "port": leader_port.split(' ')[0] if leader_port else "", # Extract only device path | |
| "id": leader_id | |
| } | |
| } | |
| try: | |
| with open(CONFIG_FILE, 'w') as f: | |
| json.dump(config, f, indent=4) | |
| return f"Configuraci贸n guardada en {CONFIG_FILE} correctamente." | |
| except Exception as e: | |
| return f"Error al guardar la configuraci贸n: {e}" | |
| def load_config(): | |
| """ | |
| Carga la configuraci贸n del robot y teleoperador desde un archivo JSON. | |
| """ | |
| if os.path.exists(CONFIG_FILE): | |
| try: | |
| with open(CONFIG_FILE, 'r') as f: | |
| config = json.load(f) | |
| return ( | |
| config.get("robot_follower", {}).get("port", ""), | |
| config.get("robot_follower", {}).get("id", ""), | |
| config.get("teleop_leader", {}).get("port", ""), | |
| config.get("teleop_leader", {}).get("id", "") | |
| ) | |
| except Exception as e: | |
| gr.Warning(f"Error al cargar la configuraci贸n existente: {e}. Se usar谩n valores por defecto.") | |
| return "", "", "", "" | |
| return "", "", "", "" | |
| # --- Gradio Interface --- | |
| # Load initial config values for Gradio components | |
| initial_follower_port, initial_follower_id, initial_leader_port, initial_leader_id = load_config() | |
| with gr.Blocks(title="Detector y Configuraci贸n de Robots LeRobot") as demo: | |
| gr.Markdown("# <center>Detector y Configuraci贸n de Robots LeRobot</center>") | |
| gr.Markdown( | |
| "Esta herramienta te ayuda a identificar los puertos seriales de tus robots " | |
| "SO101 (follower y leader) y asignarles un ID consistente." | |
| ) | |
| with gr.Tab("1. Detectar Puertos Seriales"): | |
| gr.Markdown("## Puertos Seriales Detectados") | |
| gr.Markdown( | |
| "Conecta tus robots SO101 (follower y leader) a tu computadora y haz clic en 'Refrescar Puertos'. " | |
| "Observa la lista y compara con los nombres de tus dispositivos si es posible para identificarlos." | |
| ) | |
| refresh_btn = gr.Button("馃攧 Refrescar Puertos") | |
| port_list_output = gr.Textbox( | |
| label="Puertos Seriales Disponibles", | |
| interactive=False, | |
| lines=10, | |
| value="\n".join(list_serial_ports()), # Initial list on startup | |
| show_copy_button=True | |
| ) | |
| refresh_btn.click( | |
| fn=lambda: "\n".join(list_serial_ports()), | |
| inputs=None, | |
| outputs=port_list_output | |
| ) | |
| with gr.Tab("2. Asignar Puertos e IDs"): | |
| gr.Markdown("## Asignaci贸n de Robots y Teleoperadores") | |
| gr.Markdown( | |
| "Selecciona el puerto correcto para cada dispositivo y asigna un ID 煤nico. " | |
| "**隆Es crucial usar el mismo ID en todos los scripts (grabaci贸n, entrenamiento, evaluaci贸n)!**" | |
| ) | |
| gr.Markdown("### Robot Follower (Brazo del Robot SO101)") | |
| follower_port_dropdown = gr.Dropdown( | |
| label="Puerto Serial del Robot Follower", | |
| choices=[], # Will be populated dynamically | |
| value=initial_follower_port, | |
| info="Selecciona el puerto donde est谩 conectado el brazo del robot (SO101)." | |
| ) | |
| follower_id_input = gr.Textbox( | |
| label="ID del Robot Follower", | |
| value=initial_follower_id if initial_follower_id else "my_robot_follower_arm", | |
| placeholder="ej. my_robot_follower_arm", | |
| info="Un identificador 煤nico para este robot. Usado para archivos de calibraci贸n." | |
| ) | |
| gr.Markdown("### Teleoperador Leader (Brazo de Control SO101)") | |
| leader_port_dropdown = gr.Dropdown( | |
| label="Puerto Serial del Teleoperador Leader", | |
| choices=[], # Will be populated dynamically | |
| value=initial_leader_port, | |
| info="Selecciona el puerto donde est谩 conectado el dispositivo de control (SO101)." | |
| ) | |
| leader_id_input = gr.Textbox( | |
| label="ID del Teleoperador Leader", | |
| value=initial_leader_id if initial_leader_id else "my_teleop_leader_arm", | |
| placeholder="ej. my_teleop_leader_arm", | |
| info="Un identificador 煤nico para el dispositivo de teleoperaci贸n." | |
| ) | |
| save_btn = gr.Button("馃捑 Guardar Configuraci贸n", variant="primary") | |
| save_status_output = gr.Textbox( | |
| label="Estado de Guardado", | |
| interactive=False, | |
| visible=False | |
| ) | |
| save_btn.click( | |
| fn=save_config, | |
| inputs=[follower_port_dropdown, follower_id_input, leader_port_dropdown, leader_id_input], | |
| outputs=save_status_output | |
| ) | |
| # Function to update dropdown choices based on current ports | |
| def update_port_choices(): | |
| ports = list_serial_ports() | |
| # Extract just the device path for dropdown value (e.g., /dev/tty.usbmodemXXX) | |
| device_paths = [p.split(' ')[0] for p in ports if "No se encontraron" not in p] | |
| return gr.update(choices=device_paths), gr.update(choices=device_paths) | |
| # Update dropdowns on initial load and when refresh button is clicked | |
| demo.load( | |
| fn=update_port_choices, | |
| inputs=None, | |
| outputs=[follower_port_dropdown, leader_port_dropdown] | |
| ) | |
| refresh_btn.click( # Re-bind refresh button to update dropdowns too | |
| fn=update_port_choices, | |
| inputs=None, | |
| outputs=[follower_port_dropdown, leader_port_dropdown] | |
| ) | |
| gr.Markdown("---") | |
| gr.Markdown(f"**La configuraci贸n guardada se almacenar谩 en:** `{os.path.abspath(CONFIG_FILE)}`") | |
| gr.Markdown( | |
| "**Instrucciones para otros scripts:**\n" | |
| "1. Abre `robot_config.json`.\n" | |
| "2. Copia los valores de `port` y `id` a tus scripts de `record_controller.py` y `train_robot.py` (para evaluaci贸n)." | |
| ) | |
| gr.Markdown("Hecho con 鉂わ笍 para RobotCleanPupusas503") | |
| if __name__ == "__main__": | |
| try: | |
| import serial # Test if pyserial is installed | |
| except ImportError: | |
| print("Error: La librer铆a 'pyserial' no est谩 instalada.") | |
| print("Por favor, instala 'pyserial' ejecutando: pip install pyserial") | |
| exit(1) | |
| demo.launch(share=False) |