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
- 会话 profile 过滤与持久化 —— 会话声明 profile 名称和所需的 SDK 版本,服务会在重新连接后记住这些信息;客户端和监控工具可按该 profile 过滤并定位会话。
- 按会话划分的命令缓冲区 —— 单个运行缓慢的会话不再会拖慢其他会话。
- 一次性命令的显式
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)。
HTTP
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。 - 会话选择器通配符 —— profile 名称中的
*(任意字符序列)和?(单个字符)。 - 百分号编码选择器解码 ——
%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 接收器卡死。
- 无线 Verse Grip 握手在Linux和macOS上,首次检测失败后现在会正确回退。
- macOS 配置文件位置——配置现在保存在
~/Library/Application Support/中,不再使用错误的路径。 - Linux和macOS上的 SIGSEGV 信号处理——启用多线程崩溃捕获时,进程不再对致命信号陷入循环。
- 跨会话命令覆盖——一个会话中的配置命令可能被另一个会话的命令悄然替换;现在会被正确过滤并合并。
- 探测命令覆盖配置——监控会话(例如 Haply Hub)发送
probe_position时,不再悄然覆盖待生效的 basis / preset / profile 变更。 - 原型握把显示错误——原型硬件被错误地显示为标准握把,而非自定义握把。
- 旧版
set_basis矩阵约定重新对尚未迁移的客户端生效。 - Inverse3 的 force kick 在会话断开时不再产生残余力峰值。
- 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 | Settings API |
POST /experimental/features/screensaver_enable | Settings 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 参考和硬件页面。