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