Esquema de paquete UDP
Cada paquete es un mensaje binario de longitud fija de 45 bytes. Todos los campos de múltiples bytes utilizan little-endian orden de bytes. Los bytes desconocidos añadidos al final son ignorados por el receptor para compatibilidad futura.
| campo |
Tipo |
Bytes |
Descripción |
| encabezado |
uint8[4] |
4 |
Bytes mágicos 0x52 0x43 0x54 0x50 — ASCII "RCTP". Los paquetes con un valor mágico incorrecto son descartados silenciosamente. |
| marca de tiempo |
float64 |
8 |
Unity Time.realtimeSinceStartup en segundos. Utilizado para la medición de jitter; no interpretado por el controlador del robot. |
| pos_x |
float32 |
4 |
Posición X del efector final en metros, marco del mundo VR (diestro, Y arriba). Convertido a mm marco del robot por transform_position(). |
| pos_y |
float32 |
4 |
Posición Y del efector final en metros, marco del mundo VR. |
| pos_z |
float32 |
4 |
Posición Z del efector final en metros, marco del mundo VR. |
| rot_x, rot_y, rot_z, rot_w |
float32 × 4 |
16 |
Rotación del efector final como un cuaternión unitario en el marco del mundo VR. Convertido a Euler (roll/pitch/yaw) por quat_to_euler() antes de pasar al SDK del robot. |
| pinza |
float32 |
4 |
Apertura de la pinza: 0.0 = completamente cerrada, 1.0 = completamente abierta. Derivada de la fuerza de agarre a través de VRGripperController.cs. |
| banderas |
uint8 |
1 |
Bit 0: seguimiento válido (1 = mano detectada). Bit 1: parada de emergencia solicitada (1 = operador presionó Menú). Bits restantes reservados. |
Resumen de desplazamiento de bytes: encabezado 0–3, marca de tiempo 4–11, pos_x 12–15, pos_y 16–19, pos_z 20–23, rot_x 24–27, rot_y 28–31, rot_z 32–35, rot_w 36–39, pinza 40–43, banderas 44.
Python struct cadena de formato para desempaquetar:
importar struct
PACKET_MAGIC = b'\x52\x43\x54\x50' # "RCTP"
PACKET_FMT = '<4sdfffffffff f B'
# ^ ^ ^^^^^^^^^^ ^ ^
# | | pos xyz | flags (uint8)
# | timestamp gripper (float32)
# header (4 bytes) rot xyzw (float32×4)
def analizar_paquete(data: bytes) -> dict | None:
y len(data) < struct.calcsize(PACKET_FMT):
regresar None
fields = struct.unpack_from(PACKET_FMT, data)
header, ts, px, py, pz, rx, ry, rz, rw, gripper, flags = fields
y header != PACKET_MAGIC:
regresar None
regresar {
"marca de tiempo": ts,
"posición": (px, py, pz),
"rotación": (rx, ry, rz, rw),
"garra": gripper,
"válido": bool(flags & 0x01),
"estop": bool(flags & 0x02),
}
Latencia de extremo a extremo
Medido en una red LAN Wi-Fi 6 con el brazo AgileX Piper a una tasa de control de 30 Hz y un límite de velocidad del 25%. Los valores son típicos; la latencia real depende de las condiciones de Wi-Fi y la tasa de servo del robot.
~20 ms
Pipeline de seguimiento Quest 3
Fusión de sensor de pose de mano a callback de Unity
<5 ms
Tránsito UDP
LAN Wi-Fi 6; hasta ~15 ms en Wi-Fi más antiguo
<2 ms
Análisis y cola en Python
Desempaquetado de estructura + inserción en cola
30–80 ms
Ejecución de trayectoria del robot
Depende del límite de velocidad y la distancia de movimiento
| LAN Wi-Fi 6, 25% de velocidad |
50–120 ms |
| LAN Wi-Fi 5, 25% de velocidad |
80–150 ms |
| Respuesta de parada de software (Bit 1 ruta) |
1 ciclo de control (~33 ms a 30 Hz) |
| Detección de pérdida de seguimiento |
Inmediato (byte de banderas en el paquete actual) |
Mantenga los límites de velocidad conservadores para reducir la sensación de latencia.
El componente de latencia perceptual dominante es la ejecución de la trayectoria del robot. Un menor SPEED_PERCENT hace que el sistema se sienta más predecible, aunque el tiempo de ida y vuelta real sea similar. Comience en 25% y aumente solo después de que el movimiento esté completamente validado.