v3.5.0
这是自一年前 API 重写以来规模最大的一次发布。3.5.0 版本引入了统一的 3D 数学层、对Minverse 的全面支持、带类型的事件流、完整的配置 API,以及更简洁的 HTTP 接口,同时还包含了整整一年的缺陷修复和体验优化。
亮点
- 统一的 3D 数学层——可组合的变换流水线,为设备基准坐标系(basis/frame)、挂载变换(mount transform)、工作空间变换(workspace transform)和导航变换(navigation transform)提供一等原语,并支持在本地、会话、应用和内部空间之间进行显式转换。
- 气泡导航(Bubble Navigation)—— 通过成形区域(SDF 元)在大型虚拟工作空间中进行导航,支持基于速度映射的速率控制、具备滞后感知功能的碰撞检测,以及可选的朝光标方向漂移。可通过 HTTP 和 WebSocket 进行全面配置,并支持应用空间的往返转换。
- 带类型的事件流—— 专用的 WebSocket 事件通道,涵盖设备生命周期、安全警报、校准、电池状态、控制速率警告以及停用提示。
- API 设置—— 完整的键值设置系统,支持 HTTP 的增删改查(CRUD)、类型提示、范围约束和描述信息,取代了旧的嵌套配置文件。
- 统一的设备配置 —— 所有设备共用一套 HTTP 路由:
basis、mount、preset、transform、filters、handedness、torque_scaling、gravity_compensation、home_return。 - Minverse 与笔的同步校准—— 设备及其笔现在可以一起进行校准;在校准过程中,握柄在实际安装之前将保持锁定状态。
- HTTP 的体验优化 —— 基于索引的设备选择器(通过索引指定设备,无需 ID),与 WebSocket 共享的统一请求/响应结构,可选启用
{ok, error, data}封装结构(?format=json),以及通配符会话选择器。
新功能
设备
- Minverse —— 本版本正式支持:包括检测、就绪流程、安全通知以及同步校准工作流。
- Ruko和Kingfisher已被认定为官方握把产品类型。
- 设备模拟器支持—— 可检测软件模拟设备并与之通信,同时兼容真实硬件。
- 连接循环保护 —— 行为异常的端口将被自动屏蔽;可通过
POST /ports/{port}/reset重置。 - 笔挂接心跳检测—— 借助去抖动技术实现可靠的握把挂接/拆卸检测。
会话、命令与 WebSocket
- 会话配置文件过滤与持久化—— 会话声明配置文件名称和所需的 SDK 版本,服务会在重新连接后记住这些信息;客户端和监控工具可依据该配置文件过滤并定位会话。
- 按会话划分的命令缓冲区—— 单个运行缓慢的会话不再会拖慢其他会话。
- 一次性命令的显式
configure映射 —— 每台设备的basis、preset、mount、force_gate、damping,以及每个会话的profile和basis,现在统一放入configure其中,与输出配置映射保持一致,因此发送的内容可以与读取回来的内容一一对应。 - 可自定义的设备挂载 —— 可选择内置的工作区预设(
defaults、arm_front、arm_front_centered、led_front、led_front_centered),也可以发送显式的转换;手动修改挂载后,预设会自动切换为custom。 - 命名的命令字段 ——
position、vector、angles、torques取代了通用的values数组。 set_angular_torques取代了set_angular_torque(单数形式已废止)。- 会话帧扩展 —— v3.0 和 v3.1 的会话帧现在携带可扩展的
config、state和status对象;新的输出字段包括current_cursor_force、current_cursor_position、current_angular_torques、current_angular_position、control_domain、control_mode、transform、transform_velocity、更丰富的config.*,以及status.safety(默认隐藏)。 - 部分转换更新 —— 在挂载、工作空间变换和形状导航方面,只需发送需要更改的子字段(
position、rotation、scale)。
超文本传输协定
GET /—— 服务版本。GET/POST/DELETE /settings和/settings/*—— 完整的键值设置 API。GET /sessions/{session}以及GET/POST/DELETE /sessions/{session}/profile。GET /devices?session=<selector>—— 将设备坐标转换到指定会话的应用空间中。- 基于索引的设备选择器 —— 无需知道设备 ID,即可通过索引指定任意设备(第一个Inverse3 用于
/inverse3/0/...;所有 Inverse 系列设备均采用/inverse*/*/...)。 - 统一的请求/响应结构 —— POST/GET 请求体使用与 WebSocket 相同的
command_dataJSON 结构;针对其中一种传输方式编写的代码,同样适用于另一种。 - 可选的封装结构 —— 在任意路由上添加
?format=json即可启用;/settings*和GET /home_return默认返回{ok, error, data}。如需原始结构,请使用?format=plain。 - 会话选择器通配符 —— 个人资料名称中的
*(任意字符序列)和?(单个字符)。 - 百分号编码选择器的解码 ——
%2A、%3A在路由之前,数据会被先进行解码。
事件
- 位于
communication/events/port上的专用 WebSocket 事件流。 - 共计 24 类带类型的事件,包括设备生命周期、安全事件(电子制动(e-brake)、异物检测、堵转)、校准失败、电池警报、会话警告、控制速率过低/严重过低、输入验证以及弃用提示。
可观测性
- 在进行性能分析时,日志消息会被转发到 Tracy,并根据日志级别进行着色。
- 为每个 HTTP 处理函数添加 Tracy 区域。
- 主循环用于计时和统计事件。
- 可配置日志目录和服务器主机名(以便 Docker 使用)。
3.6 版本即将发布
- SDF 触觉效果(SDF HFX)—— 基础工作已在 3.5 版本中完成(模块、生命周期、模块提供的命令/状态序列化),公开 API 及完整文档将随 3.6 版本发布。
改进
- 力振荡滤波—— 逐轴振荡检测、8 阶段渐进式恢复、带滞后的进入投票,以及非对称的释放窗口。
- 运行时力门控滤波器 —— 可通过
configure.force_gate.gain在 WebSocket 或 HTTP 上进行配置,并带有持久化的默认值。 - 主循环的最高频率提升至 32 kHz,适用于高精度应用。
- 更小的 WebSocket 负载 —— 恒等(identity)默认值的转换子字段(
position = 0、rotation = identity、scale = 1)默认不再输出,从而减小负载体积,并恢复与旧版 Unity 数据包 4 KB 消息上限的兼容性。两个高级设置(serialization/explicit_fields、serialization/force_complete_transforms)可为有需要的用户重新启用所有字段。 - 降低主循环抖动—— WebSocket 消息处理在 JSON 解析和网络发送期间不再阻塞主循环的节拍;会话节拍调度已移至响应序列化之前。
- 服务器默认仅监听 localhost —— 如需访问网络,请通过
communication/bind_all_interfaces设置已开启。 - 设备选择器通配符改用前缀语法(例如
inverse*(可与所有 Inverse 系列设备兼容)。 - 阻尼指令 已移入
configure在映射中,与force_gate放在一起。 - 轮转文件日志器取代了原有的日志器,并支持配置目录。
- 模块贡献的命令与状态—— 模块可以注入自己的命令、配置字段,并将状态输出写入 WebSocket 帧,而无需修改核心 schema。
修复
一整年的缺陷修复;其中影响最大的修复如下所示。
- 会话速度异常,在特定条件下出现。
- **GripHook(Verse Grip Stopper)**在未运行仿真时无法顺利释放。
- Inverse3 超时设置过于激进,导致启动较慢的设备陷入断连循环。
- 在 Windows 上,服务停止得不彻底——关机时并不总能清理 HTTP 服务器。
- 重连循环——当服务向较旧的固件版本发送不受支持的命令时会出现。
- 在安装了蓝牙适配器的系统上,蓝牙设备枚举会产生大量日志。
- 连续多次重启服务时发生崩溃。
- Ubuntu 笔记本在休眠/唤醒后,无线 Verse Grip 接收器出现卡死现象。
- 在Linux和macOS上,无线 Verse Grip 握把在首次检测失败后,现在会正确回退。
- macOS 配置文件的位置——配置目前保存在
~/Library/Application Support/其中,不再使用错误的路径。 - Linux 和 macOS 上的 SIGSEGV 信号处理——启用多线程崩溃捕获后,进程将不再因致命信号而陷入循环。
- 跨会话命令覆盖——一个会话中的配置命令可能会被另一个会话中的命令悄然替换;现在这些命令会被正确过滤并合并。
- 探测命令覆盖配置——监控会话(例如Haply Hub)发送
probe_position此时,将不再悄然覆盖待生效的 basis / preset / profile 更改。 - 原型握把显示错误——原型硬件被错误地显示为标准握把,而非自定义握把。
- 旧版
set_basis矩阵约定对尚未迁移的客户端重新生效。 - Inverse3 当会话断开时 ,“力踢”将不再产生残余力峰值。
- WebSocket 连接丢失的竞争条件——出现在快速连接/断开循环期间。
- WebSocket
session_id在部分出站负载中被序列化为0。 - 在Windows上,同时使用
--dev现在将遵循--log-level(此前会被悄然重置为debug)。
已弃用项
仍可正常使用,但将在未来的重大版本中移除。在适用情况下,响应中将包含 deprecation_warning 字段。
| 已弃用 | 备选方案 |
|---|---|
POST /force_scale | POST /settings/devices/inverse*/filters/force_scale/gain |
POST /gravity_compensation | POST /{device}/{id}/config/gravity_compensation |
POST /torque_scaling | POST /{device}/{id}/config/torque_scaling |
POST /device_handedness | POST /{device}/{id}/config/handedness |
POST /serial_enable | POST /settings/communication/serial/enabled |
POST /experimental/features/grip_dropped_simulation_stopper | 设置 API |
POST /experimental/features/screensaver_enable | 设置 API |
WebSocket command_data.values | position, vector, angles, torques |
WebSocket set_angular_torque | set_angular_torques |
WebSocket probe_cursor_position | probe_position |
WebSocket set_coordinate_origin | configure.preset |
WebSocket 会话级 set_basis | configure.basis |
兼容性说明
与 3.4.19 相比,本次更新不存在强制性的破坏性变更。针对现有集成,有两点温和的提示:
- 已弃用的 HTTP 端点现在会在响应中包含
deprecation_warning字段——严格验证响应 schema 的客户端应允许该额外字段。 - WebSocket
command_data中的values该字段已被弃用,但仍会被解析;建议优先使用命名字段。
教程与文档
- 新增教程:05 位置控制、06 组合(Inverse3 + Verse Grip)、07 基准与安装、08 HTTP 远程配置器、09 WebSocket 远程控制、10 事件流监听器。
- 为每个 C++ 教程新增 Glaze 变体(
cpp-glz/),与现有的 nlohmann/json 变体并存。 - 所有教程均已根据 v3.1 API 重写(端口 10001、
configure.preset、命名命令字段、print_state()辅助函数)。 - 已删除旧版的Verse Grip Stopper 教程,并由新的综合教程取代。
- 公开文档已更新,涵盖 SDK 指南、API 参考和硬件页面。