Skip to content
FORSENSE

UDP Reception – EMF Poses

This document describes the EMF sensor pose and magnetic-transmitter IMU protocol sent by HumanHand over UDP.

1. Overview

ItemDescription
OutputFive finger EMF poses, an optional forearm pose, and magnetic-transmitter IMU
TransportUDP unicast, connectionless
Rate120 Hz by default
ProtocolFNIM, version 2
Packet size240 bytes, fixed
HandOne 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

ParameterDefaultDescription
Destination IP127.0.0.1Configurable in Data Sending
Destination port15001Configurable in Data Sending
Byte orderLittle-endianUsed 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)

ItemDescription
OriginMagnetic transmitter on that glove
AxesRFU (Right-Forward-Up)
Position unitmillimeters (mm)
RotationQuaternion w, x, y, z

RFU (Right-Forward-Up) hand-local axes:

AxisMeaning
XRight: pinky-to-thumb for the left hand; thumb-to-pinky for the right hand
YForward, toward fingertips
ZUp, 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

FieldUnitAxes
accel_mps2m/s²RFU (Right-Forward-Up), as defined in §3.1
gyro_radpsrad/sRFU (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.

IndexNameDescription
0thumbThumb
1indexIndex finger
2middleMiddle finger
3ringRing finger
4pinkyPinky
5forearmOptional forearm slot; valid=0 if disconnected or uncalibrated

5. Packet Structure

5.1 Layout

text
Offset 0   : header (24 bytes)
Offset 24  : 6 sensor slots (192 bytes)
Offset 216 : magnetic-transmitter IMU (24 bytes)
Total      : 240 bytes

5.2 Header (24 bytes)

OffsetSizeTypeFieldDescription
04uint32magic0x464E494D ("FNIM")
41uint8version2
51uint8flags1=left, 2=right, 0=invalid
62uint16reserved0
84uint32frame_numberFrame counter
128uint64timestamp_nsHost monotonic-clock nanoseconds
204uint32quat_order0x77787A79 (wxyz)

5.3 flags

ValueMeaning
0Invalid; discard
1Left hand
2Right hand

5.4 Slot Record (32 bytes, i = 0..5)

Relative offsetFieldTypeDescription
0position_mm.x/y/zfloat32×3Millimeters
12quaternion.w/x/y/zfloat32×4wxyz
28validuint81=valid
29reserveduint8[3]0

Use a slot pose only when valid == 1.

5.5 Magnetic-Transmitter IMU (24 bytes)

Relative offsetFieldTypeUnit
0accel_mps2.x/y/zfloat32×3m/s²
12gyro_radps.x/y/zfloat32×3rad/s

6. Timestamp and Frame Number

FieldMeaning
timestamp_nsMonotonic-clock nanoseconds, suitable for interval and jitter measurements
frame_numberLoss 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

  1. Require a packet length of 240.
  2. Require magic == 0x464E494D and version == 2.
  3. Require quat_order == 0x77787A79.
  4. Require flags to be 1 or 2.
  5. Use only slots where valid == 1.
  6. 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

c
#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

ItemEMF + transmitter IMUJoint poses (FSNH)
MagicFNIM version 2FSNH version 4
Packet size240 B612 B (wrist) / 640 B (forearm)
Content6 slot poses + transmitter IMU21 or 22 joints/hand
Position unitMillimetersMeters
Coordinate systemMagnetic-transmitter tracking frameWrist-relative (left RFU / right LBU)
Two handsSeparate left and right packetsSeparate left and right packets
TimestampMonotonic-clock nanosecondsMonotonic-clock nanoseconds

Copyright © 2026 Forsense. All rights reserved.