Skip to content
FORSENSE

UDP接收-关节位姿

本文档说明 HumanHand 上位机SDK 演示程序发出的关节 UDP。点序、轴向与 SDK 读到的数组相同。接入自己的程序时,也可以不经 UDP,直接读 SDK。

1. 功能概述

输出格式原点每手点数协议单包大小
关节位姿(相对手腕)掌根21FSNH 版本 4612 字节
关节位姿(相对小臂)小臂模块22FSNH 版本 4640 字节
项目说明
数据来源手套关节位姿;小臂档需接小臂模块
传输协议UDP 单播,无握手
输出频率默认 120 Hz(每只手各自按解算节拍发)
手别一包一只手hand=1 左,hand=2
双手同一目的 IP 和端口,左右各发一包。接收端按 hand 分到两只手。两包不必同时到达

上位机路径:用户设置 → 数据发送 → 输出格式。SDK 演示菜单:相对手腕 / 相对小臂发关节。

2. 发送配置

参数默认值说明
目标 IP127.0.0.1上位机在「数据发送」中修改;SDK 演示启动时询问
目标端口15001双手共用这一端口
字节序小端(Little-Endian)所有多字节字段

3. 坐标系说明

项目说明
相对手腕原点在掌根(与 SDK hh_sdk_poll 相同)
相对小臂原点在小臂(与 SDK hh_sdk_forearm_root 相同);轴与手腕档相同
位置单位米(m)
旋转四元数 w, x, y, z
轴向左手:右、前、上;右手:左、后、上
左手右手
X
Y前(沿手指)
Z上(手背方向)

载荷里只有这一只手的关节,按 hand 选用。

4. 关节索引

4.1 相对手腕(21)

载荷索引部位
0掌根(位置约 0)
1–4拇指:掌指、近节、远节、指尖
5–8食指
9–12中指
13–16无名指
17–20小指

指尖:4、8、12、16、20

4.2 相对小臂(22)

载荷索引部位
0小臂(位置恒为 0,姿态为单位四元数)
1手腕(即上面的掌根)
2–21上面的 1–20(拇指掌指 … 小指指尖)

指尖:5、9、13、17、21

5. 数据包结构

包头 24 字节,随后本手全部关节。每关节 28 字节:xyz(12)+ wxyz(16)。

text
相对手腕:24 + 21×28 = 612
相对小臂:24 + 22×28 = 640

发送字节数必须等于上表。不要按最大结构体长度截取或补零。

5.1 包头(24 字节)

偏移大小类型字段说明
04uint32magic0x464E4853"FSNH"
41uint8version4
51uint8hand1 左 / 2
61uint8joint_count21 相对手腕,22 相对小臂
71uint8status见 5.2
84uint32frame_index该手自己的帧序号
128uint64timestamp_ns主机单调时钟纳秒
204uint32quat_order0x77787A79(wxyz)

包长也可区分:612=手腕,640=小臂。须与 joint_count 一致。

5.2 status

掩码含义
00x011=本包是新解算;0=重复上一拍
10x02仅 22 点:1=本拍小臂原点有效;0=沿用上次有效小臂。21 点时为 0
2–7必须为 0

5.3 单关节(28 字节)

相对偏移字段类型
0position.x/y/zfloat32×3
12quaternion.w/x/y/zfloat32×4

从偏移 24 起连续 joint_count 个。

6. 双手怎么收

  1. 只绑定一个 UDP 端口(默认 15001)。
  2. 每收到一包,读 hand:1 写入左手缓存,2 写入右手缓存。
  3. 左右的 frame_index / timestamp_ns 各自独立,不要拿来互相对齐成「同一瞬间」。
  4. 某一侧暂时没有新包,继续用该侧上一包;不要用另一侧的数据填。

7. 时间戳与发送频率

字段含义
timestamp_ns主机单调时钟纳秒
frame_index该手解算序号;停滞时不再增加

默认约 8.33 ms 一包(每只手 120 Hz)。双手时该端口上大约每秒 240 个数据报。

8. 接收端检查清单

  1. magic == 0x464E4853version == 4
  2. 长度 612joint_count==21,或长度 640joint_count==22
  3. hand 为 1 或 2
  4. quat_order == 0x77787A79
  5. status 高 6 位为 0
  6. 只解析本包 joint_count 个关节

9. C 结构体参考

接入时按下列结构体组包或拆包。

c
#pragma pack(push, 1)

#define FSNH_MAGIC            0x464E4853u
#define FSNH_VERSION          4u
#define FSNH_HAND_LEFT        1u
#define FSNH_HAND_RIGHT       2u
#define FSNH_JOINTS_WRIST     21u
#define FSNH_JOINTS_FOREARM   22u
#define FSNH_STATUS_NEW       0x01u
#define FSNH_STATUS_FOREARM_LIVE 0x02u
#define FSNH_PKT_WRIST        612u
#define FSNH_PKT_FOREARM      640u
#define FSNH_QUAT_ORDER_WXYZ  0x77787A79u

typedef struct {
    float x, y, z;
    float qw, qx, qy, qz;
} FsnhJointPose;

typedef struct {
    uint32_t magic;
    uint8_t  version;
    uint8_t  hand;
    uint8_t  joint_count;
    uint8_t  status;
    uint32_t frame_index;
    uint64_t timestamp_ns;
    uint32_t quat_order;
} FsnhHeader;

typedef struct {
    FsnhHeader header;
    FsnhJointPose joints[FSNH_JOINTS_WRIST];
} FsnhPacketWrist;

typedef struct {
    FsnhHeader header;
    FsnhJointPose joints[FSNH_JOINTS_FOREARM];
} FsnhPacketForearm;

#pragma pack(pop)

发送手腕包时只发出 sizeof(FsnhPacketWrist)(612)字节。

10. 参考接收脚本

站点提供 udp_receiver.py,上位机默认端口 15001

bash
python3 udp_receiver.py --port 15001

按包长显示当前格式:612/640 关节,240 线圈+IMU,1860 Pico 全身。双手同一端口左右各一包,脚本按手各刷一块表,大约每秒原地刷新。

11. 与「EMF + 发射源 IMU」对比

对比项关节位姿EMF + 发射源 IMU
协议FSNH 版本 4FNIM 版本 2
包长612 B(腕)/ 640 B(小臂)240 B
内容21 或 22 关节/手6 槽位姿 + 发射源 IMU
位置单位毫米
坐标系左 RFU / 右 LBU磁源跟踪系
双手同一端口,左右各一包左右各一包
时间戳单调时钟纳秒单调时钟纳秒

Copyright © 2026 Forsense. All rights reserved.