IMU UDP 协议与时间模型¶
本文是根目录 PROTOCOL.md 的中文公开文档入口,定义当前二进制 UDP 姿态包和上位机动捕链路使用的时间字段。所有多字节包字段均为小端序。
UDP 通道¶
通道 |
端口 |
方向 |
用途 |
|---|---|---|---|
数据 |
4211 |
设备到主机 |
二进制姿态包和文本状态 |
发现 |
4212 |
设备广播 |
|
发现信标格式为:
VQF_DISC,node=<MAC后缀>,id=<可选设备ID>,ip=<IP>,tcp=4210,udp=4211,ver=<固件版本>
设备同时通过 mDNS 发布 _vqf-imu._tcp 服务,主机名为 vqf-imu-<node_id>.local。
v1 姿态包¶
type = 0x01,长度必须恰好为 12 字节:
偏移 |
类型 |
字段 |
|---|---|---|
0 |
|
|
1 |
|
|
2 |
|
|
4 |
|
Q15 四元数 |
Python 格式为 "<BBH4h",Q15 解码为 value / 32767.0。seq 只能在同一设备内判断丢包,不能比较不同 IMU 的采样先后。
v2 姿态包¶
type = 0x03,长度必须恰好为 20 字节:
偏移 |
类型 |
字段 |
|---|---|---|
0 |
|
|
1 |
|
|
2 |
|
|
4 |
|
|
12 |
|
Q15 四元数 |
Python 格式为 "<BBHQ4h"。
sensor_time_us 是设备自启动后的单调微秒时钟,必须在 IMU 采样或 VQF 姿态更新处记录,不能在 UDP 发送时生成。它不是 Unix 时间;在完成跨设备时钟同步之前,不能直接比较不同设备的该字段。
当前固件发送 v2 0x03 包。上位机继续兼容旧固件的 v1 0x01 包;v1 节点不能参与共同时间轴解算。
文本状态包¶
type = 0x02,至少为 4 字节:
偏移 |
类型 |
字段 |
|---|---|---|
0 |
|
|
1 |
|
保留 |
2 |
|
包序列号 |
4 |
UTF-8 字节 |
以空字符结尾的文本载荷 |
设备用该包发送低频消息,例如 $CAL,...、$PWR,... 和 $DIAG,...。
主机时间字段¶
字段 |
含义 |
|---|---|
|
|
|
有效时钟映射后的主机单调采样时刻;映射无效时为 |
|
后续共同时间轴动捕帧的递增 ID。 |
|
后续用于解算一帧身体姿态的共同目标时刻。 |
|
后续人体解算完成的主机单调时刻。 |
|
至少 4 个有效样本且时间跨度不小于 3 秒时,节点到主机的时钟映射有效。 |
|
有效样本线性拟合的 RMS 残差估计;未知时为 |
|
一帧共同动捕中最旧有效样本年龄;尚未计算时为 |
Unix 墙上时间只用于日志和界面显示。实时排序、在线超时和包频率统计使用主机单调时钟。
TCP 命令¶
主机连接 TCP 4210 后发送以换行符结尾的文本命令:
命令 |
用途 |
|---|---|
|
开始磁力计标定采集 |
|
停止标定采集 |
|
擦除已保存标定参数 |
|
请求设备关机 |
|
保存自定义设备 ID |
|
查询自定义设备 ID |
|
时间同步请求,TCP 直接回复 |
TCP 时间同步¶
主机仅对已发送 v2 姿态包的节点执行同步。每 10 秒对每个节点连续发起 4 次:
主机发送
$CMD,SYNC,<nonce>前记录t0_host_ns。设备 TCP 接收任务收到完整行后立即记录
t1_device_us,回复前记录t2_device_us。主机收到
$SYNC,<nonce>,<t1_us>,<t2_us>后记录t3_host_ns。主机拟合
host_monotonic_ns ~= scale * sensor_time_us + offset。
RTT 大于 50 ms 或相对最佳 RTT 明显偏大的样本会被丢弃。offset 消除不同开机时刻,scale 补偿晶振误差和长期漂移。未达到有效条件时,仅显示各节点最新姿态,不将它们视为同一采样时刻。
共同动捕时间轴¶
人体解算不会直接拼接各节点刚收到的“最新姿态”。对于已同步的 v2 节点,主机保留短时缓存并选择:
t_target = min(latest_sample_time[node]) - safety_margin
默认 safety_margin 为 20 ms。胸部、上臂、小臂和手掌都必须在 t_target 前后拥有间隔不大于 80 ms 的两个样本,系统以最短路径 SLERP 插值得到共同帧。任一必需节点缺失、未同步、缓存不足或样本过旧时,共同帧明确无效,不能混用旧姿态和新姿态。
MocapState.frame_time_ns 即 t_target;node_samples 保留插值前后序号、时间、插值比例和样本年龄;time_sync_error_us 和 max_sample_age_ms 分别给出这一帧最差同步误差和最老前向样本年龄。
OTA¶
OTA HTTP 服务监听 8080 端口:
请求 |
用途 |
|---|---|
|
以 |
|
查询 OTA / 设备信息 |
上传必须使用原始固件二进制请求体,不支持 multipart 表单上传。