Aplicación de escritorio SCS0009 (GUI y CLI)
Esta página es el tutorial de control de escritorio de la versión con bus serie SCS0009. Para el control web, consulta Control web SCS0009; para el cableado de hardware, Cableado SCS0009.
Inicio rápido
- Instala Python 3.10+ y las dependencias: Instalación.
- Conecta la placa controladora de bus y confirma el puerto serie: Requisitos del entorno.
- Ejecuta la GUI:
amazing-hand-guiopython amazing_hand_gui.py. - Según Calibración, comprueba la mano izquierda/derecha, los ángulos y la posición central.
- Usa los deslizadores por dedo, las poses predefinidas y las secuencias para hacer movimientos.
Herramienta de control AmazingHand en Python (compatible con mano izquierda y derecha)
Herramienta GUI y de línea de comandos escrita en Python que controla 8 servos Feetech SCS0009 a través de una placa controladora de servos de bus serie, accionando la mano diestra AmazingHand de Pollen Robotics.
Compatible con ambas manos. Al iniciar, elige la mano derecha (ID de servo 1-8) o la izquierda (ID de servo 11-18); --hand permite omitir la pregunta. La biblioteca de poses es común a ambas manos; cada mano mantiene su propio mapeo de servos, desfase de montaje y valores objetivo raw en data/config.yaml. Consulta la selección de mano izquierda/derecha.

Estructura del proyecto
amazing_hand_gui.py – Programa principal de la GUI
amazing_hand_cmd.py – Herramienta de línea de comandos
hand_logic.py – Lógica de negocio compartida (independiente de la UI)
pyproject.toml – Metadatos del paquete, dependencias, configuración de pytest
data/
config.yaml – Ajustes de la aplicación (puerto serie, límites, objetivos raw)
hand_config.yaml – Gestos y secuencias guardados
docs/
REQUIREMENTS.md – Requisitos y criterios de aceptación
CONFIG_FORMAT.md – Descripción del formato de configuración
scs_servo_protocol.md – Referencia de registros del SCS0009
CHANGES.md – Cambios respecto al original y sus motivos
user_manual.md – Página de redirección al tutorial central
tests/
test_hand_logic.py – Pruebas unitarias de hand_logic (155)
test_gui_utils.py – Pruebas unitarias de utilidades de la GUI (51)
test_cmd.py – Pruebas unitarias de la CLI (42)
test_integration.py – Pruebas de integración (14)
test_system.py – Pruebas de sistema con subprocesos (22)
test_system_hardware.py – Pruebas de hardware (33, requiere --hardware)
test_cmd_hardware.py – Pruebas de hardware de la CLI (21, requiere --hardware)Requisitos del entorno
- Python 3.10 o superior (la GUI necesita Tkinter)
- Fuente externa independiente de 5 V para los 8 servos
- Adaptador de bus serie USB con el controlador instalado
Instalación
Se recomienda instalar con pip (lee pyproject.toml):
pip install -e .O instalar directamente las dependencias:
pip install -r requirements.txtEntorno de desarrollo y pruebas:
pip install -r requirements-dev.txtCalibración
El sistema de ángulos, las poses predefinidas y la posición central de los servos dependen de la mano concreta. Todos estos parámetros están centralizados en data/config.yaml.
Selección de mano izquierda/derecha
Las dos manos usan servos y estructuras mecánicas distintas, así que hay que elegir antes de que aparezca la interfaz:
AmazingHand — which hand?
1 = right hand (servo IDs 1-8)
2 = left hand (servo IDs 11-18)
Enter 1 or 2 [1]:
LEFT hand — servo IDs 11-18
Ring (11, 12) Middle (13, 14) Pointer (15, 16) Thumb (17, 18)
middle position raw: [571, 451, 571, 451, 571, 451, 571, 451]Omitir la pregunta:
python amazing_hand_gui.py --hand left
python amazing_hand_cmd.py --pose victory --hand leftSi no se añade --hand, se usa el valor hand: de data/config.yaml.
Por qué una mano no es solo cambiar el grupo de ID. Además de la numeración de servos (derecha 1-8, izquierda 11-18, y en la izquierda la numeración de dedos está espejada: el anular va primero), la mano izquierda tiene dos diferencias mecánicas que el programa gestiona automáticamente:
| Mano derecha | Mano izquierda | |
|---|---|---|
| ID de servo | 1-8 | 11-18 |
| Dedo → ID | Índice 1,2 / Medio 3,4 / Anular 5,6 / Pulgar 7,8 | Anular 11,12 / Medio 13,14 / Índice 15,16 / Pulgar 17,18 |
| MiddlePos del fabricante | [451, 571, …] | [571, 451, …] |
| Desfase de montaje | 0° | −35.16° (hands.left.angle_offset) |
| Doble servo del mismo dedo | (a, b) | (b, a) (hands.left.mirror_pose) |
Si falta cualquiera de los dos últimos, los gestos se deforman: el desfase de montaje desvía cada dedo 35°, y sin el intercambio dentro del dedo la dirección de apertura se invierte por completo (en el gesto de V los dos dedos se juntan y los tres que deberían juntarse se abren).
data/hand_config.yaml es común a ambas manos y siempre guarda el orden de la mano derecha; la izquierda se convierte al leer y se vuelve a convertir al guardar.
Calibrar una mano nueva. Usa los valores de hands.left como plantilla y verifica en este orden:
- Pulsa Middle position y comprueba si la fila Current (0-1023) lee los valores raw esperados
- Pulsa Open All / Close All — el recorrido debe llegar al límite mecánico sin bloquearse
- Prueba un gesto de apertura (victory forma una V, greeting junta tres dedos)
Qué parámetro ajustar si algo no cuadra:
| Síntoma | Dónde cambiar |
|---|---|
| La lectura de Middle position no es correcta | hands.<nombre>.raw_positions.middle |
| La dirección de apertura está invertida | hands.<nombre>.mirror_pose |
| El recorrido es insuficiente o se pasa | hands.<nombre>.raw_positions.open / close |
Sistema de ángulos
Tanto la GUI como la CLI usan valores de ángulo, que el controlador rustypot convierte en los valores raw internos del servo:
raw = 1024 × angle / 300° + 511 (0.29297°/step, rango raw 0–1023)| Ángulo | Significado |
|---|---|
| −35° | Completamente abierto (extendido) |
| 0° | Posición central, dedo ligeramente flexionado de forma natural |
| +75° | Completamente cerrado (puño) |
Los dos servos de cada dedo van uno al lado del otro con ejes colineales: el giro en el mismo sentido produce abducción (splay) y el giro en sentidos opuestos produce flexión. El servo de ID par está negado respecto al impar, así que un mismo valor de apertura/cierre hace que los dos servos se muevan en direcciones opuestas; el programa lo gestiona automáticamente y no tienes que convertirlo a mano.
Límites
limits:
servo_min: -75 # límite absoluto de recorrido para cualquier comando de servo
servo_max: 75
base_min: -75 # rango del deslizador de apertura/cierre
base_max: 75
side_min: -35 # rango del deslizador lateral
side_max: 35side_min/side_max controlan la apertura lateral. Como el programa normaliza (u = |side_offset| / |side_min|), cambiar solo este rango no modifica la amplitud real de apertura, únicamente comprime la escala del deslizador. Para cambiar de verdad el ángulo de apertura del dedo hay que modificar también auto_extremes.
Objetivos raw
Los tres botones de posición global llevan los servos a valores raw exactos, sin pasar por el modelo de ángulos:
raw_positions: # índice 0 -> ID de servo 1 …… índice 7 -> ID de servo 8
open: [260, 760, 260, 760, 260, 760, 260, 760]
close: [760, 260, 760, 260, 760, 260, 760, 260]
middle: [451, 571, 451, 571, 451, 571, 451, 571]- open / close — los dos extremos del recorrido mecánico. Se miden accionando cada servo por separado con la herramienta de depuración Feetech del fabricante.
- middle — la posición central mecánica calibrada (es decir, MiddlePos del programa de demostración Arduino del fabricante). Ojo: no es el punto medio entre open y close, sino que se desvía unos ±60 raw (±17,6°) respecto a raw 511.
Estos son los valores de calibración de cada mano. El fabricante lo dice así: "replace values by your calibration results".
Cómo verificarlo: el panel Servo Feedback tiene una fila Current (0-1023) que muestra la posición raw en tiempo real. Tras pulsar el botón Middle position, esa fila debería leer 451, 571, 451, 571, ….
Resumen de rangos de los controles
| Control | Rango |
|---|---|
| Deslizador de apertura/cierre (vertical) | −75 … +75 |
| Deslizador lateral (horizontal) | −35 … +35 |
| Velocidad | 1 (lento) … 6 (rápido) |
El valor de velocidad lo pasa el controlador al servo como rad/s, así que 1–6 corresponde aproximadamente a 57–344 °/s. Con carga, la velocidad real es de aproximadamente el 70% de ese valor — tenlo en cuenta al calcular los retardos de la secuencia.
Ejecutar la GUI (amazing_hand_gui.py)

La interfaz se divide en cuatro zonas:
- Columna izquierda: paneles de control por dedo para los cuatro dedos, con deslizadores de apertura/cierre y lateral, modos Auto/Raw, velocidad y Open/Close/Center.
- Columna central: botones de control global (Open All / Close All / Center All / Middle position) y gestión de poses.
- Columna derecha: curvas de telemetría y tabla de realimentación Servo Feedback (posición, carga, temperatura, voltaje).
- Parte inferior: registro de ejecución y barra de estado, con el estado de conexión, el progreso de la acción y los mensajes de error.
Tras instalar con pip se puede invocar directamente:
amazing-hand-gui
amazing-hand-gui --port /dev/ttyUSB0O ejecutar directamente:
python amazing_hand_gui.py
python amazing_hand_gui.py --port /dev/ttyUSB0El desplegable de puertos lista los puertos serie que existen realmente en la máquina (primero con pyserial; si no está, lee el registro de Windows), así que también aparecen los adaptadores con números más altos. También se puede escribir el puerto directamente en el desplegable. Si el puerto por defecto de la configuración no está conectado, la GUI arranca automáticamente con el primer puerto real; si quieres fijar el puerto, pásalo explícitamente con --port.
Funciones

Control por dedo con deslizadores de apertura/cierre y lateral, compatible con dos modos: Auto (apertura/cierre + lateral) y Raw (control directo de los ángulos de los dos servos)
En modo Auto los dos deslizadores son ejes de control y el programa hace automáticamente la composición diferencial; el modo Raw es el que da directamente los ángulos de los dos servos. Los dos servos de cada dedo van uno al lado del otro con ejes colineales: el giro en el mismo sentido produce splay y el giro en sentidos opuestos produce flexión.
Botones rápidos Open / Close / Center por dedo
Selección de velocidad por dedo (1–6), además de un desplegable de velocidad global
Atajos de teclado para ajustes precisos
Botones de posición global: Open All, Close All, Center All, Middle position
Gestión de gestos y secuencias basada en data/hand_config.yaml
Eliminación directa de gestos guardados desde la interfaz (botón 🗑 Delete)
Curvas de telemetría de servo en tiempo real (posición, carga, temperatura, voltaje)
Tabla Servo Feedback con posición raw en tiempo real (0–1023), útil para verificar la calibración
Operación con teclado
- 1-4: seleccionar dedo (Ring anular, Middle medio, Pointer índice, Thumb pulgar)
- Teclas de dirección: mover el dedo seleccionado
- Arriba/abajo: cerrar / abrir
- Izquierda/derecha: mover lateralmente
- Teclas modificadoras:
- Ninguna: 1° por pulsación (ajuste fino)
- Shift: 5° por pulsación (normal)
- Ctrl: 10° por pulsación (rápido)
- Acciones rápidas:
- Q: cerrar completamente el dedo seleccionado
- E: abrir completamente el dedo seleccionado
- C: volver a la posición lateral centrada
Botones globales
| Botón | Apertura/cierre | Lateral |
|---|---|---|
| ✋ Open All | Todos los dedos al raw open | Centrar |
| ✊ Close All | Todos los dedos al raw close | Centrar |
| ⊙ Center All | Sin cambios | Centrar |
| ⊙ Middle position | Todos los dedos al raw middle | Centrar |
El desplegable Global Speed (1–6) aplica inmediatamente la velocidad seleccionada a todos los controles de dedo y sincroniza la visualización de los deslizadores de cada dedo.
Los tres botones de valores raw (Open All, Close All, Middle position) se saltan el modelo de ángulos, por lo que tras ejecutarlos los deslizadores muestran el valor representable más cercano, no el valor exacto. Si después tocas un deslizador, la mano se desvía hasta unos 0,3° del objetivo raw — es una concesión deliberada para acertar con precisión las posiciones calibradas.
Problema conocido: Center All no omite los dedos en modo Raw y sobrescribe los ángulos raw que hayas ajustado manualmente. El botón ⊙ Center de un solo dedo sí los omite.
Ejecutar la CLI (amazing_hand_cmd.py)
Herramienta de línea de comandos independiente; permite aplicar gestos y reproducir secuencias sin iniciar la GUI. Lee el mismo data/hand_config.yaml que la GUI y envía literalmente los valores de pose guardados, exactamente igual que la GUI.
Linux: permisos del puerto serie
El adaptador de puerto serie USB suele aparecer como /dev/ttyACM0 (Waveshare / CDC-ACM) o /dev/ttyUSB0 (FTDI / CH340).
Para encontrarlo:
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
# o bien
dmesg | grep -E 'ttyACM|ttyUSB' | tail -5Si aparece Permission denied, añade el usuario actual al grupo dialout y vuelve a iniciar sesión:
sudo usermod -aG dialout $USERTras instalar con pip
amazing-hand-cmd --list
amazing-hand-cmd --pose open
amazing-hand-cmd --sequence demo --loop
amazing-hand-cmd --pose open --speed 6
# sobrescribir el puerto serie si es necesario:
amazing-hand-cmd --pose open --port /dev/ttyUSB0Ejecución directa
python amazing_hand_cmd.py --list
python amazing_hand_cmd.py --pose open
python amazing_hand_cmd.py --pose close --speed 6
python amazing_hand_cmd.py --sequence demo
python amazing_hand_cmd.py --sequence wave --loop
python amazing_hand_cmd.py --port /dev/ttyUSB0 --pose open
python amazing_hand_cmd.py --list --config /path/to/hand_config.yamlParámetros
| Parámetro | Valor por defecto | Descripción |
|---|---|---|
| --pose NAME | – | Aplica el gesto con el nombre indicado |
| --sequence NAME | – | Reproduce la secuencia con el nombre indicado |
| --list | – | Lista todos los gestos y secuencias |
| --loop | desactivado | Reproduce la secuencia en bucle hasta Ctrl+C |
| --speed N | 3 | Velocidad del servo 1 (lento)… 6 (rápido) |
| --port PORT | Linux /dev/ttyACM0 Windows COM9 | Número de puerto del puerto serie |
| --baudrate N | 1000000 | Velocidad en baudios |
| --config PATH | data/hand_config.yaml | Especifica otro archivo de configuración |
| --hand | hand de config.yaml | Indica qué mano usar (derecha 1-8, izquierda 11-18) |
Al salir del script (incluido Ctrl+C) se desactiva automáticamente el par de todos los servos.
La CLI no tiene un parámetro --config correspondiente a data/config.yaml; ese archivo se carga siempre desde el directorio del proyecto.
Archivos de configuración
data/config.yaml
| Sección | Uso |
|---|---|
| serial | Puerto serie por defecto de cada plataforma, velocidad en baudios, lista de velocidades disponibles |
| servos | ID de servo correspondiente a cada dedo |
| limits | Rangos de ángulo de los servos y de los dos deslizadores |
| speeds | Valores por defecto/mínimo/máximo de la escala de velocidad 1–6 |
| auto_extremes | Posición de los servos cuando los deslizadores laterales llegan al límite |
| raw_positions | Objetivos raw exactos de los botones de posición global |
| paths | Ubicación de los archivos de gestos/secuencias |
Correspondencia entre servos y dedos
| Dedo | ID de servo | Índice del array de pose |
|---|---|---|
| Pointer índice | 1, 2 | 4, 5 |
| Middle medio | 3, 4 | 2, 3 |
| Ring anular | 5, 6 | 0, 1 |
| Thumb pulgar | 7, 8 | 6, 7 |
El orden del array de pose es anular, medio, índice, pulgar, no el orden de ID de servo. Este es el punto más fácil de confundir al editar hand_config.yaml a mano.
El comentario al principio de amazing_hand_cmd.py dice "index 0→servo1 … 7→servo8", ese comentario es incorrecto; la tabla anterior refleja el comportamiento real del código.
Gestos y secuencias

Todos los gestos y secuencias se guardan en data/hand_config.yaml. Si el archivo no existe, la GUI lo crea automáticamente.
Guardar un gesto
- Coloca la mano en la pose objetivo con los deslizadores o el teclado
- Escribe un nombre en el campo "Name:"
- Pulsa "➕ Add New" en la zona Pose Management
La velocidad solo afecta a la rapidez con que se mueven los deslizadores; el gesto guardado solo registra las 8 posiciones de servo.
Cargar / eliminar gestos
- Selecciona en el desplegable y pulsa ✓ Apply para que la mano se mueva a esa pose
- Pulsa 🗑 Delete a la derecha de Apply y confirma para eliminarla permanentemente
Gestión de secuencias
- En Sequence Player, pulsa "🔧 Manage" para abrir el gestor de secuencias
- Saved Sequences (columna izquierda)
- Ver, ejecutar, editar o eliminar secuencias existentes
- Haz doble clic o pulsa "▶ Execute" para ejecutarla una vez
- Sequence Builder (columna derecha)
- Haz doble clic en un gesto de "Available Poses" para añadirlo como paso
- Puedes ajustar la velocidad y el retardo de los 8 servos de cada paso; los pasos se guardan como "pose:s1,s2,...,s8|delay"
- Usa ↑/↓ para cambiar el orden o pulsa "⏱ Delay" para insertar una pausa independiente
- Escribe un nombre y pulsa "💾 Save Sequence" para guardar; pulsa "▶ Execute" para probar sin guardar
- Vuelve a la ventana principal y marca Loop en Sequence Player si quieres reproducción continua

Formato de paso
pose_name:speed1,speed2,...,speed8|delay- speed1..speed8 — velocidades de los 8 servos (1–6) en el orden de la pose
- delay — tiempo de espera hasta el siguiente paso, p. ej. 0.6s. Se puede omitir; si se omite, la GUI vuelve a una espera automática fija
- Una pausa independiente se escribe SLEEP:1.0s (sin lista de velocidades separada por comas)
Cómo elegir el retardo. El controlador puede leer si el servo ha llegado a pararse, pero la reproducción de secuencias usa retardos fijos. Calcula aproximadamente recorrido_angular / (velocidad × 57.3 × 0.7) segundos y deja margen — en una mano con carga, un movimiento de más de unos 130° tarda más de 1,0 s a velocidad 3.
Ejemplo de formato YAML
poses:
open:
positions: [-35, -35, -35, -35, -35, -35, -35, -35]
close:
positions: [75, 75, 75, 75, 75, 75, 75, 75]
ring_close: # anular cerrado, el resto abierto
positions: [75, 75, -35, -35, -35, -35, -35, -35]
sequences:
demo:
steps:
- "open:3,3,3,3,3,3,3,3|2.0s"
- "close:6,6,6,6,6,6,6,6|2.0s"
- "ok:3,3,3,3,3,3,3,3|1.0s"
- "victory:3,3,3,3,3,3,3,3|1.0s"
- "greeting:3,3,3,3,3,3,3,3|1.5s"
- "close:6,6,6,6,6,6,6,6|2.0s"
wave:
steps:
- "open:6,6,6,6,6,6,6,6|0.8s"
- "wave_r:5,5,5,5,5,5,5,5|0.6s"
- "wave_l:5,5,5,5,5,5,5,5|0.6s"
- "open:5,5,5,5,5,5,5,5|0.8s"
finger_roll:
steps:
- "open:6,6,6,6,6,6,6,6|0.5s"
- "ring_close:5,5,5,5,5,5,5,5|0.6s"
- "open:5,5,5,5,5,5,5,5|0.5s"
- "middle_close:5,5,5,5,5,5,5,5|0.6s"
- "open:5,5,5,5,5,5,5,5|0.5s"La reproducción en bucle la controla el tiempo de ejecución (la casilla de la GUI) y ya no se escribe en el YAML.
Pruebas
El proyecto incluye 284 pruebas unitarias/de integración/de sistema y 54 pruebas de hardware.
Ejecutar todas las pruebas (sin hardware)
pytestEjecutar las pruebas de hardware de GUI + CLI (requiere servos conectados)
pytest tests/test_system_hardware.py --hardware --port /dev/ttyACM0
pytest tests/test_cmd_hardware.py --hardware --port /dev/ttyACM0
# o ambas a la vez:
pytest tests/test_system_hardware.py tests/test_cmd_hardware.py --hardwaretest_system_hardware.py verifica la conexión, la aplicación de gestos, la lectura de telemetría, la apertura/cierre y el saludo de un dedo, el control de velocidad, la ejecución de secuencias y la detección de movimiento.
test_cmd_hardware.py verifica de extremo a extremo la capa CLI: posiciones de pose, parámetros de velocidad, pasos de secuencia, wait_for_motion, salida de --list y desactivación del par al salir.
Los criterios de aceptación completos están en Requisitos de aceptación y pruebas.
Nota: las pruebas sin hardware comprueban los valores por defecto de reserva de hand_logic.py, que siguen la escala original −40…110. En tiempo de ejecución, data/config.yaml los sobrescribe, así que las pruebas pasan independientemente de cómo calibres — pero eso también significa que las pruebas no validan tus parámetros de calibración actuales.
Configuración del ID de servo
Tutorial para configurar el ID de servo con el software oficial de Feetech y la placa controladora de bus serie: https://www.robot-maker.com/forum/tutorials/article/168-brancher-et-controler-le-servomoteur-feetech-sts3032-360/
Descarga del software Feetech: https://github.com/Robot-Maker-SAS/FeetechServo
Telemetría y realimentación
- Selección de métricas: posición, carga, velocidad, temperatura, voltaje, indicador de movimiento.
- Modos de gráfico: Multi-Servo (curvas de varios servos) y Scope (osciloscopio de un solo canal).
- Zoom/desplazamiento: Y Zoom / Pan, Time Zoom / Pan.
- Tabla de realimentación: Goal, Position, Speed, Load, Voltage, Temperature, Status, Moving.


Editor de secuencias
- En Sequence Player, pulsa Manage.
- Añade pasos con Available Poses, ajusta la velocidad por dedo, el retardo del paso o inserta una pausa.
- Usa ↑/↓ para cambiar el orden, escribe un nombre y guarda; también puedes probar primero con Execute.
- Vuelve a la ventana principal, selecciona la secuencia y pulsa Play; activa Loop para reproducción continua.
La definición de las secuencias está bajo la clave sequences de data/hand_config.yaml.
Solución de problemas
| Síntoma | Sugerencia |
|---|---|
| No aparece ningún puerto serie | Vuelve a conectar el adaptador USB, instala el controlador o reinicia la GUI. |
| El botón Connect está gris | Ya está conectado; pulsa primero Disconnect. |
| Redimensionar la ventana se traba | Cierra ventanas innecesarias; el cambio de tamaño ya tiene antirrebote/limitación. |
| La secuencia no mueve todos los dedos | Comprueba la velocidad de cada paso y asegúrate de que cada pose incluya los valores de los 8 servos. |
| El indicador de bloqueo permanece activo | Comprueba si hay obstrucción mecánica; se activa cuando la diferencia entre objetivo y posición real es grande y no hay movimiento. |
Documentación de desarrollo relacionada
- Formato de configuración (YAML)
- Tabla de memoria del protocolo SCS0009
- Cambios de diseño y notas de calibración
- Requisitos de aceptación y pruebas
Agradecimientos
Proyecto original: Betatester777 Hardware y firmware de referencia: Pollen Robotics

