UDP Reception – EMF Poses
This document describes the EMF sensor pose and magnetic-transmitter IMU protocol sent by HumanHand over UDP.
1. Overview
| Item | Description |
|---|---|
| Output | Five finger EMF poses, an optional forearm pose, and magnetic-transmitter IMU |
| Transport | UDP unicast, connectionless |
| Rate | 120 Hz by default |
| Protocol | FNIM, version 2 |
| Packet size | 240 bytes, fixed |
| Hand | One hand per packet; two hands are sent as separate left and right packets |
In HumanHand, open User Settings → Data Sending and select Coil Poses + IMU (FNIM v2).
2. Sending Configuration
| Parameter | Default | Description |
|---|---|---|
| Destination IP | 127.0.0.1 | Configurable in Data Sending |
| Destination port | 15001 | Configurable in Data Sending |
| Byte order | Little-endian | Used by all multibyte fields |
3. Coordinate System
EMF sensor poses and magnetic-transmitter IMU data are both expressed in a hand-local coordinate system.
3.1 EMF Sensor Poses (Relative to the Transmitter on that Glove)
| Item | Description |
|---|---|
| Origin | Magnetic transmitter on that glove |
| Axes | RFU (Right-Forward-Up) |
| Position unit | millimeters (mm) |
| Rotation | Quaternion w, x, y, z |
RFU (Right-Forward-Up) hand-local axes:
| Axis | Meaning |
|---|---|
| X | Right: pinky-to-thumb for the left hand; thumb-to-pinky for the right hand |
| Y | Forward, toward fingertips |
| Z | Up, from palm toward back of hand |
Both hands are relative to the transmitter on their own glove and use the RFU hand-local axes above.
3.2 Magnetic-Transmitter IMU
| Field | Unit | Axes |
|---|---|---|
| accel_mps2 | m/s² | RFU (Right-Forward-Up), as defined in §3.1 |
| gyro_radps | rad/s | RFU (Right-Forward-Up), as defined in §3.1 |
These fields are 0 when no transmitter IMU is received.
4. Sensor Indices
Each packet has 6 slots of 32 bytes each.
| Index | Name | Description |
|---|---|---|
| 0 | thumb | Thumb |
| 1 | index | Index finger |
| 2 | middle | Middle finger |
| 3 | ring | Ring finger |
| 4 | pinky | Pinky |
| 5 | forearm | Optional forearm slot; valid=0 if disconnected or uncalibrated |
5. Packet Structure
5.1 Layout
Offset 0 : header (24 bytes)
Offset 24 : 6 sensor slots (192 bytes)
Offset 216 : magnetic-transmitter IMU (24 bytes)
Total : 240 bytes5.2 Header (24 bytes)
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 4 | uint32 | magic | 0x464E494D ("FNIM") |
| 4 | 1 | uint8 | version | 2 |
| 5 | 1 | uint8 | flags | 1=left, 2=right, 0=invalid |
| 6 | 2 | uint16 | reserved | 0 |
| 8 | 4 | uint32 | frame_number | Frame counter |
| 12 | 8 | uint64 | timestamp_ns | Host monotonic-clock nanoseconds |
| 20 | 4 | uint32 | quat_order | 0x77787A79 (wxyz) |
5.3 flags
| Value | Meaning |
|---|---|
| 0 | Invalid; discard |
| 1 | Left hand |
| 2 | Right hand |
5.4 Slot Record (32 bytes, i = 0..5)
| Relative offset | Field | Type | Description |
|---|---|---|---|
| 0 | position_mm.x/y/z | float32×3 | Millimeters |
| 12 | quaternion.w/x/y/z | float32×4 | wxyz |
| 28 | valid | uint8 | 1=valid |
| 29 | reserved | uint8[3] | 0 |
Use a slot pose only when valid == 1.
5.5 Magnetic-Transmitter IMU (24 bytes)
| Relative offset | Field | Type | Unit |
|---|---|---|---|
| 0 | accel_mps2.x/y/z | float32×3 | m/s² |
| 12 | gyro_radps.x/y/z | float32×3 | rad/s |
6. Timestamp and Frame Number
| Field | Meaning |
|---|---|
| timestamp_ns | Monotonic-clock nanoseconds, suitable for interval and jitter measurements |
| frame_number | Loss and reordering detector |
At the default 120 Hz, packet spacing is approximately 8.33 ms.
7. Two-Hand Mode
- Left-hand packet:
flags = 1 - Right-hand packet:
flags = 2
Two packets may be received consecutively. Process them separately according to flags.
8. Receiver Checklist
- Require a packet length of 240.
- Require
magic == 0x464E494Dandversion == 2. - Require
quat_order == 0x77787A79. - Require
flagsto be 1 or 2. - Use only slots where
valid == 1. - Use the transmitter IMU at the end of the packet; it may be all zero when no valid IMU is available.
9. C Structure Reference
#pragma pack(push, 1)
#define FNIM_MAGIC 0x464E494Du
#define FNIM_VERSION 2u
#define FNIM_PKT_SIZE 240u
#define FNIM_SLOTS 6u /* 0..4 fingers, 5 forearm */
typedef struct {
float px, py, pz; /* mm */
float qw, qx, qy, qz; /* wxyz */
uint8_t valid;
uint8_t reserved[3];
} FnimSlot;
typedef struct {
uint32_t magic;
uint8_t version;
uint8_t flags;
uint16_t reserved;
uint32_t frame_number;
uint64_t timestamp_ns;
uint32_t quat_order;
} FnimHeader;
typedef struct {
FnimHeader header;
FnimSlot slots[FNIM_SLOTS];
float accel_mps2[3]; /* Transmitter IMU */
float gyro_radps[3];
} FnimPacket;
#pragma pack(pop)10. Reference implementation
The site provides udp_receiver.py (same script and default port 15001 as joints). After the host is set to coil pose + IMU, it prints six coils (millimetres) and the transmitter IMU.
Joint-pose packets: UDP Reception – Joint Poses.
11. Comparison with Joint Poses
| Item | EMF + transmitter IMU | Joint poses (FSNH) |
|---|---|---|
| Magic | FNIM version 2 | FSNH version 4 |
| Packet size | 240 B | 612 B (wrist) / 640 B (forearm) |
| Content | 6 slot poses + transmitter IMU | 21 or 22 joints/hand |
| Position unit | Millimeters | Meters |
| Coordinate system | Magnetic-transmitter tracking frame | Wrist-relative (left RFU / right LBU) |
| Two hands | Separate left and right packets | Separate left and right packets |
| Timestamp | Monotonic-clock nanoseconds | Monotonic-clock nanoseconds |
