File size: 7,336 Bytes
5ed0597
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# 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)