UDP-Paketschema
Jedes Paket ist eine 45-Byte-Binärnachricht fester Länge. Alle Multibyte-Felder verwenden Little-Endian Byte-Reihenfolge. Am Ende angehängte unbekannte Bytes werden vom Empfänger aus Gründen der Vorwärtskompatibilität ignoriert.
| Feld |
Typ |
Bytes |
Beschreibung |
| Kopfzeile |
uint8[4] |
4 |
Magische Bytes 0x52 0x43 0x54 0x50 — ASCII „RCTP“. Pakete mit einem falschen magischen Wert werden stillschweigend verworfen. |
| Zeitstempel |
float64 |
8 |
Einheit Time.realtimeSinceStartup in Sekunden. Wird zur Jitter-Messung verwendet. nicht von der Robotersteuerung interpretiert. |
| pos_x |
float32 |
4 |
Endeffektor-X-Position in Metern, VR-Weltrahmen (rechtshändig, Y-oben). Umgerechnet in mm Roboterrahmen von transform_position(). |
| Sträußchen |
float32 |
4 |
Y-Position des Endeffektors in Metern, VR-Weltrahmen. |
| pos_z |
float32 |
4 |
Z-Position des Endeffektors in Metern, VR-Weltrahmen. |
| rot_x, rot_y, rot_z, rot_w |
float32 × 4 |
16 |
Endeffektorrotation als Einheitsquaternion im VR-Weltrahmen. Umgerechnet in Euler (Rollen/Nicken/Gieren) von quat_to_euler() bevor es an das Roboter-SDK übergeben wird. |
| Greifer |
float32 |
4 |
Greiferöffnung: 0.0 = vollständig geschlossen, 1.0 = vollständig geöffnet. Abgeleitet von der Pinch-Stärke über VRGripperController.cs. |
| Flaggen |
uint8 |
1 |
Bit 0: Tracking gültig (1 = Hand erkannt). Bit 1: Notstopp angefordert (1 = Bediener hat Menü gedrückt). Restliche Bits reserviert. |
Byte-Offset-Zusammenfassung: Header 0–3, Zeitstempel 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, Gripper 40–43, Flags 44.
Python struct Formatstring zum Entpacken:
Import 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 parse_packet(data: bytes) -> dict | None:
Wenn len(data) < struct.calcsize(PACKET_FMT):
zurückkehren None
fields = struct.unpack_from(PACKET_FMT, data)
header, ts, px, py, pz, rx, ry, rz, rw, gripper, flags = fields
Wenn header != PACKET_MAGIC:
zurückkehren None
zurückkehren {
„Zeitstempel“: ts,
"Position": (px, py, pz),
"Drehung": (rx, ry, rz, rw),
„Greifer“: gripper,
"gültig": bool(flags & 0x01),
„Sicherungen“: bool(flags & 0x02),
}
End-to-End-Latenz
Gemessen in einem Wi-Fi 6 LAN mit dem AgileX Piper-Arm bei 30 Hz Steuerfrequenz und 25 % Geschwindigkeitsbegrenzung. Werte sind typisch; Die tatsächliche Latenz hängt von den WLAN-Bedingungen und der Servogeschwindigkeit des Roboters ab.
~20 ms
Quest 3-Tracking-Pipeline
Handpose-Sensorfusion zum Unity-Rückruf
<5 ms
UDP-Transit
Wi-Fi 6 LAN; bis zu ~15 ms bei älterem WLAN
<2 ms
Python-Analyse und Warteschlange
Struktur entpacken + Warteschlange einfügen
30–80 ms
Ausführung der Roboterbahn
Hängt von der Geschwindigkeitsbegrenzung und der Bewegungsdistanz ab
| Wi-Fi 6 LAN, 25 % Geschwindigkeit |
50–120 ms |
| Wi-Fi 5 LAN, 25 % Geschwindigkeit |
80–150 ms |
| Software Not-Aus-Reaktion (Bit 1 Pfad) |
1 Regelzyklus (~33 ms bei 30 Hz) |
| Erkennung von Tracking-Verlusten |
Sofort (Flaggen-Byte im aktuellen Paket) |
Halten Sie die Geschwindigkeitsbegrenzungen konservativ, um das Latenzgefühl zu reduzieren.
Die dominierende Komponente der Wahrnehmungslatenz ist die Ausführung der Roboterbahn. Eine niedrigere SPEED_PERCENT Dadurch fühlt sich das System vorhersehbarer an, auch wenn die tatsächliche Umlaufzeit ähnlich ist. Beginnen Sie bei 25 % und erhöhen Sie den Wert erst, nachdem die Bewegung vollständig bestätigt wurde.