Haply Inverse3 是一套集成了关节传感器、力矩执行器、安全监控机制与实时控制环的三自由度桌面力反馈机器人系统。Haply 官方 Inverse SDK 采用「本地服务进程 + WebSocket/HTTP 协议 」的分层架构,将底层串口通信、设备固件交互与安全防护封装在后台服务中,应用层仅通过标准化 JSON 协议即可实现高频力控。

一、设备本质:认识 Inverse3 小型机器人系统
从机器人系统的视角看,Inverse3 是一套完整的串联式三自由度力反馈执行机构,具备感知、控制、执行与安全防护全链路能力,而非单纯的输入外设。其核心属性可从五个维度定义:
| 系统维度 | 核心能力 | 工程意义 |
|---|---|---|
| 感知层 | 实时采集末端笛卡尔位置/速度、关节角度/角速度、当前输出力 | 为控制算法提供闭环反馈输入,所有力控计算均基于实时状态 |
| 执行层 | 支持笛卡尔空间力控制、位置控制,以及关节空间力矩控制 | 可适配不同交互场景,从柔顺力反馈到刚性位置约束均可实现 |
| 通信层 | 应用层通过 WebSocket/HTTP 与本地服务交互,底层由服务完成串口通信 | 业务代码与硬件解耦,支持多语言、多平台接入 |
| 安全层 | 内置通信超时、异常力检测、未校准保护、断电保护等多重安全机制 | 人机直接交互场景下的基础安全保障 |
| 交互层 | 人手直接接触末端执行器,力反馈直接作用于人体 | 控制算法必须考虑人体感知与操作安全,禁止无限制输出大力 |
官方文档明确指出,Inverse SDK 的设计目标是将硬件复杂性封装在本地服务中,使开发者专注于上层交互逻辑开发,同时通过标准化协议保障控制的实时性与安全性。
二、软件架构与通信链路
2.1 整体分层架构
Inverse3 的软件栈采用典型的分层设计,从上到下分为应用层、服务层、固件层与硬件层,开发者通常仅需与服务层交互:
#mermaid-svg-rPVxcK1DO4Nn8bX8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .error-icon{fill:#552222;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .marker.cross{stroke:#333333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 p{margin:0;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .cluster-label text{fill:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .cluster-label span{color:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .cluster-label span p{background-color:transparent;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .label text,#mermaid-svg-rPVxcK1DO4Nn8bX8 span{fill:#333;color:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .node rect,#mermaid-svg-rPVxcK1DO4Nn8bX8 .node circle,#mermaid-svg-rPVxcK1DO4Nn8bX8 .node ellipse,#mermaid-svg-rPVxcK1DO4Nn8bX8 .node polygon,#mermaid-svg-rPVxcK1DO4Nn8bX8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .rough-node .label text,#mermaid-svg-rPVxcK1DO4Nn8bX8 .node .label text,#mermaid-svg-rPVxcK1DO4Nn8bX8 .image-shape .label,#mermaid-svg-rPVxcK1DO4Nn8bX8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .rough-node .label,#mermaid-svg-rPVxcK1DO4Nn8bX8 .node .label,#mermaid-svg-rPVxcK1DO4Nn8bX8 .image-shape .label,#mermaid-svg-rPVxcK1DO4Nn8bX8 .icon-shape .label{text-align:center;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .node.clickable{cursor:pointer;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .arrowheadPath{fill:#333333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rPVxcK1DO4Nn8bX8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rPVxcK1DO4Nn8bX8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rPVxcK1DO4Nn8bX8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .cluster text{fill:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .cluster span{color:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rPVxcK1DO4Nn8bX8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .icon-shape,#mermaid-svg-rPVxcK1DO4Nn8bX8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .icon-shape p,#mermaid-svg-rPVxcK1DO4Nn8bX8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .icon-shape .label rect,#mermaid-svg-rPVxcK1DO4Nn8bX8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rPVxcK1DO4Nn8bX8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rPVxcK1DO4Nn8bX8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rPVxcK1DO4Nn8bX8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} WebSocket / HTTP + JSON
USB 串口通信
硬件驱动
电机
编码器
力反馈机构
Inverse3 嵌入式固件
Inverse Service
(本地服务进程)
用户应用程序
(上位机 / Web 前端)
该架构的核心优势在于:
- 硬件抽象 :应用层无需直接操作串口设备文件(如
/dev/ttyACM0、COM 口),避免底层兼容问题 - 安全隔离:服务层统一负责安全监控,异常时可直接切断力输出,不受上层程序崩溃影响
- 多语言兼容:只要支持 WebSocket 与 JSON 解析的语言均可接入,官方已验证 Python、C++、C#、Rust 等多种语言
2.2 Haply Hub 与 Inverse Service 的定位
两者是包含与被包含的关系,职责边界清晰:
- Haply Hub:设备管理与调试工具集,集成设备识别、固件更新、状态可视化、Demo 测试、服务启停等功能,面向开发者调试与设备运维场景。官方建议新手通过 Hub 完成设备安装、配置与测试验证。
- Inverse Service :核心后台服务,是应用程序的直接交互对象。其核心职责包括设备发现、串口通信、安全监控、实时状态流推送、控制命令处理 ,可嵌入 Hub 运行,也可独立部署为系统服务(Windows Service、Linux Daemon、macOS LaunchDaemon)。

2.3 通信端口与通道定义
官方标准端口分配如下,所有通道均运行在本地环回地址:
| 通道类型 | 端口 | 传输协议 | 核心用途 |
|---|---|---|---|
| 仿真控制通道 | 10001 | WebSocket | 实时命令-状态闭环控制,是力控开发的核心通道 |
| 系统事件通道 | 10020 | WebSocket | 单向推送设备连接、安全触发、控制率异常、校准状态等系统事件 |
| 配置管理接口 | 10001 | HTTP REST | 设备查询、会话管理、参数配置等非实时操作 |
三、通信协议机制
3.1 WebSocket 实时控制通道:一发一收同步模型
WebSocket 仿真通道是力控开发的核心,其协议机制与 ROS Topic 的订阅-推送模式有本质区别:服务端每收到一条客户端命令消息,才返回一帧设备状态更新;无命令输入则无状态输出,控制频率完全由客户端发送频率决定。
这意味着即使仅需读取设备位置而不输出力,也必须持续发送保活命令(通常为零力指令),否则无法获取状态更新。标准控制循环的时序为:
⚙️ 设备端 🖥️ 控制客户端 ⚙️ 设备端 🖥️ 控制客户端 #mermaid-svg-dWm2CAAnIaVVugVz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dWm2CAAnIaVVugVz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dWm2CAAnIaVVugVz .error-icon{fill:#552222;}#mermaid-svg-dWm2CAAnIaVVugVz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dWm2CAAnIaVVugVz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dWm2CAAnIaVVugVz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dWm2CAAnIaVVugVz .marker.cross{stroke:#333333;}#mermaid-svg-dWm2CAAnIaVVugVz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dWm2CAAnIaVVugVz p{margin:0;}#mermaid-svg-dWm2CAAnIaVVugVz .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dWm2CAAnIaVVugVz text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-dWm2CAAnIaVVugVz .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-dWm2CAAnIaVVugVz .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-dWm2CAAnIaVVugVz .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-dWm2CAAnIaVVugVz .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-dWm2CAAnIaVVugVz #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-dWm2CAAnIaVVugVz .sequenceNumber{fill:white;}#mermaid-svg-dWm2CAAnIaVVugVz #sequencenumber{fill:#333;}#mermaid-svg-dWm2CAAnIaVVugVz #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-dWm2CAAnIaVVugVz .messageText{fill:#333;stroke:none;}#mermaid-svg-dWm2CAAnIaVVugVz .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dWm2CAAnIaVVugVz .labelText,#mermaid-svg-dWm2CAAnIaVVugVz .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-dWm2CAAnIaVVugVz .loopText,#mermaid-svg-dWm2CAAnIaVVugVz .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-dWm2CAAnIaVVugVz .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-dWm2CAAnIaVVugVz .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-dWm2CAAnIaVVugVz .noteText,#mermaid-svg-dWm2CAAnIaVVugVz .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-dWm2CAAnIaVVugVz .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dWm2CAAnIaVVugVz .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dWm2CAAnIaVVugVz .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dWm2CAAnIaVVugVz .actorPopupMenu{position:absolute;}#mermaid-svg-dWm2CAAnIaVVugVz .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-dWm2CAAnIaVVugVz .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dWm2CAAnIaVVugVz .actor-man circle,#mermaid-svg-dWm2CAAnIaVVugVz line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-dWm2CAAnIaVVugVz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🔗 阶段一:建立连接 📡 阶段二:获取初始快照 🔑 核心动作: 解析并存储 device_id 🔄 阶段三:核心控制循环 (持续迭代) 💾 更新状态缓存,准备下一轮迭代 loop每一帧控制周期 WebSocket 握手请求 (Upgrade)1101 协议切换成功2首帧完整设备快照3确认接收 (ACK)4📖 1. 读取上一帧状态数据5🧮 2. 计算控制力 (动力学/运动学)6📤 3. 发送控制命令 (携带 device_id)7📥 4. 返回新一帧状态数据8
该模型的工程价值在于:控制闭环的时序完全由应用层掌控,避免了异步推送带来的状态与命令不同步问题,更适合确定性力控算法。
3.2 HTTP 接口:非实时配置管理
HTTP REST 接口仅用于无状态的配置与查询操作,不适合高频实时控制,典型适用场景包括:
- 查询已连接设备列表与基本信息
- 读取与修改设备配置参数(坐标系映射、重力补偿、扭矩缩放等)
- 会话生命周期管理
- 固件版本与设备状态查询
官方提供了完整的配置项 CRUD 接口,支持预设、坐标系基底、安装方式、滤波器等参数的读写与重置。
四、设备生命周期与状态体系
4.1 标准启动与校准流程
正确的设备启动流程是保障力控准确性与安全性的前提,官方推荐操作顺序为:
- 启动 Haply Hub 或 Inverse Service
- 连接 USB-C 数据线(建议直连主板,避免扩展坞引入通信延迟)
- 接入 24V 直流电源
- 等待 Hub 识别设备,状态灯由红转紫
- 完成磁体校准:将末端云台的磁体触碰底座校准点,直至状态灯变白
- 启动用户应用程序建立控制连接
校准并非形式化步骤,其直接决定位置与力的映射精度:未校准状态下坐标不可信、力反馈方向可能偏移,设备也不会进入可控制状态。
4.2 状态灯语义:硬件级调试入口
设备顶部的状态灯是最直观的硬件状态指示器,开发者可通过灯光快速判断设备运行阶段与异常原因:

注意:如果状态指示灯持续亮红灯,可能是您的 USB 设备无法传输数据。请确保连接牢固,或更换数据线
4.3 状态数据字段解析
WebSocket 首帧会返回完整的设备快照,包含 config、state、status 三类数据,基础开发阶段需重点关注以下核心字段:
| 字段路径 | 数据含义 | 工程用途 |
|---|---|---|
device_id |
设备唯一标识 | 所有命令必须指定目标设备 ID |
state.cursor_position |
末端笛卡尔位置 | 虚拟弹簧、虚拟墙等力控算法的核心输入 |
state.cursor_velocity |
末端笛卡尔速度 | 阻尼项计算、异常状态判断 |
state.current_cursor_force |
当前实际输出力 | 控制效果观测与闭环校验 |
status.calibrated |
校准状态标志 | 未校准状态下禁止输出控制力 |
status.ready |
设备就绪标志 | 非就绪状态下禁止控制 |
status.power_supply |
电源接入标志 | 无外接电源时力控不可用 |
status.in_use |
设备占用标志 | 检测是否被其他会话占用,避免多程序抢设备 |
4.4 坐标系与单位规范
Inverse3 采用右手笛卡尔坐标系,Z 轴向上 ,默认朝向为:+X 向右、+Y 向前、+Z 向上。官方支持通过 basis 配置项进行坐标系映射,自动完成应用坐标系与设备内部坐标系的双向转换。
核心物理量单位严格遵循国际单位制:
| 物理量 | 单位 | 说明 |
|---|---|---|
| 笛卡尔位置 | 米(m) | 末端工作空间范围约为百毫米级 |
| 笛卡尔速度 | 米/秒(m/s) | 用于阻尼力计算 |
| 笛卡尔力 | 牛顿(N) | 持续大力建议不超过 8N |
| 关节角度 | 度(°) | 关节空间控制使用 |
| 关节角速度 | 度/秒(°/s) | 关节空间阻尼计算 |
| 关节力矩 | 牛·米(N·m) | 关节空间力矩控制使用 |
五、控制指令体系
5.1 configure 与 commands 的边界
WebSocket 指令分为两类,生命周期与作用域完全不同,开发者需严格区分:
configure配置指令 :一次性参数设置,写入后持续生效,直至下次修改。
典型配置包括坐标系基底、安装方向、滤波器参数、重力补偿开关等。commands控制指令 :单帧生效的瞬时指令,应用后即被遗忘,需每帧持续发送。
典型指令包括笛卡尔力设置、位置控制、关节力矩设置等。
工程上可简化记忆:configure 负责改设备参数,commands 负责控制当前帧的输出。
5.2 零力控制:安全基线
零力指令(zero force)并非无操作,而是明确告知设备当前帧输出 0N 力,其标准 JSON 格式如下:
json
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": { "x": 0.0, "y": 0.0, "z": 0.0 }
}
}
}
]
}
零力控制是整个力控系统的安全基线,必须遵循以下工程规范:
- 程序启动建立连接后,先发送零力指令再进入控制循环
- 正常退出、异常捕获、断连重连时,优先发送零力指令
- 设备非就绪状态下,仅发送零力指令或不发送任何力指令
- 程序退出逻辑中必须包含零力发送步骤,防止残留力输出
六、基础力控算法
6.1 虚拟弹簧:力反馈入门模型
虚拟弹簧是最基础的力反馈交互模型,其物理本质为胡克定律,通过位移偏差产生回复力,常用于回中引导、柔顺约束等场景。
标准三维弹簧-阻尼模型公式 :
F=−k⋅(p−p0)−b⋅v \boldsymbol{F} = -k \cdot (\boldsymbol{p} - \boldsymbol{p}_0) - b \cdot \boldsymbol{v} F=−k⋅(p−p0)−b⋅v
其中:
- kkk 为弹簧刚度系数(单位:N/m),决定拉回力度
- p\boldsymbol{p}p 为当前末端位置,p0\boldsymbol{p}_0p0 为弹簧平衡点
- bbb 为阻尼系数(单位:N·s/m),用于抑制振荡
- v\boldsymbol{v}v 为当前末端速度
工程实践要点:
- 刚度从小到大逐步调试,初始建议 10~20 N/m,避免高刚度引发振荡
- 必须添加阻尼项,纯弹簧系统极易产生高频震荡,损伤设备与用户体验
- 输出力必须做幅值限幅,防止程序异常导致大力输出
- 平衡点需设置在设备工作空间中心区域,避免超出机械行程
6.2 虚拟墙:约束型交互模型
虚拟墙是典型的单边约束交互,仅当末端穿透边界时产生反向排斥力,常用于工作空间边界限制、虚拟物体碰撞反馈等场景。
平面虚拟墙算法 :
设墙面法向量为 n\boldsymbol{n}n(单位向量),墙面上一点为 p0\boldsymbol{p}_0p0,当前末端位置为 p\boldsymbol{p}p,则穿透深度为:
d=(p−p0)⋅n d = (\boldsymbol{p} - \boldsymbol{p}_0) \cdot \boldsymbol{n} d=(p−p0)⋅n
当 d>0d > 0d>0 时表示穿透墙面,输出法向排斥力:
F=(−k⋅d−b⋅(v⋅n))⋅n \boldsymbol{F} = (-k \cdot d - b \cdot (\boldsymbol{v} \cdot \boldsymbol{n})) \cdot \boldsymbol{n} F=(−k⋅d−b⋅(v⋅n))⋅n
当 d≤0d \le 0d≤0 时输出力为 0。
常见问题与规避:
- 刚度过高易引发接触抖动,需配合阻尼与低通滤波
- 穿透深度突变会导致力跳变,可加入软过渡区域
- 必须确保法向量方向正确,反向会导致力方向完全错误
官方安全文档特别强调,高刚度虚拟约束易造成系统不稳定,必须从低刚度开始逐步上调,出现失控时立即切断电源。
七、实时性与控制频率
7.1 力反馈的实时性本质
力反馈交互的体验质量高度依赖控制频率与延迟稳定性。人体触觉感知带宽可达数百赫兹,通常认为 1kHz 以上的控制率才能提供顺滑、无颗粒感的力反馈体验,低于 500Hz 会明显感知到卡顿与离散感。
Inverse Service 本身支持千赫兹级的触觉控制率,状态通过 WebSocket 高频传输,上层程序的计算与序列化开销是控制频率的主要瓶颈。
7.2 影响控制频率的工程因素
基础开发阶段需关注以下性能损耗点:
- JSON 序列化/反序列化开销:高频场景下建议使用高性能 JSON 库(如 C++ 的 Glaze、Python 的 orjson),官方教程对比过不同库在 4kHz 控制环下的性能差异。
- 打印与日志输出:控制台打印会严重阻塞控制循环,调试时需做降频处理。
- 语言运行时特性:Python 的 GC、全局解释器锁会引入抖动,高频控制场景推荐使用 C++。
- 阻塞式逻辑:控制循环内禁止加入 IO 操作、耗时计算等阻塞逻辑。
八、安全工程与异常处理体系
力反馈设备直接与人手交互,安全是第一优先级。建立完整的异常感知与安全退出机制非常重要。
8.1 异常场景与应对策略
| 异常场景 | 触发原因 | 标准处理流程 |
|---|---|---|
| WebSocket 连接失败 | Inverse Service 未启动、端口被占用 | 提示启动服务,程序优雅退出 |
| 设备未识别 | USB 未接、设备故障、驱动异常 | 检查硬件连接,不进入控制循环 |
| 设备非就绪 | 未校准、无电源、被占用 | 禁止输出力,提示用户处理 |
| 设备断连 | 线缆脱落、设备断电 | 立即停止力计算,清理状态退出 |
| 安全触发 | 异常力、超行程、通信超时 | 立即停止控制,提示用户排查 |
| 控制率过低 | 程序卡顿、计算量过大 | 降低计算复杂度,必要时降级或退出 |
系统事件通道(端口 10020)会主动推送设备生命周期、安全告警、控制率异常等事件,建议同时监听该通道以实现更快的异常响应。
8.2 标准安全退出流程
程序必须实现统一的安全退出函数,覆盖正常退出、信号中断、异常捕获等所有退出路径,标准执行顺序为:
- 置位运行标志,停止生成新的控制力
- 尝试发送零力指令,清空当前输出
- 关闭 WebSocket 连接
- 清理线程、资源与日志
- 输出退出状态提示
需特别注意:当物理通信中断时,零力指令可能无法送达设备。因此真正的安全防护是系统性的:每帧限幅、每帧状态校验、异常立即停控、硬件层面兜底保护,而非仅依赖最后一帧零力指令。
8.3 强制安全开发规则
基础开发阶段必须严格遵守以下安全规范,形成工程习惯:
- 所有输出力必须做幅值限幅,禁止无限制输出
- 位置、速度数据出现 NaN、无穷大等异常值时,立即停止输出
- 未校准、无电源、非就绪状态下,绝对不输出控制力
- 刚度参数从小到大调试,禁止一开始使用高刚度
- 禁止长时间持续输出 8N 以上的大力,避免设备发热与寿命损耗
- 禁止多个程序同时连接同一设备,避免指令冲突
- 必须保留物理紧急停止手段(电源开关),软件安全不能替代硬件断电
九、工程化架构建议与验收标准
9.1 分层代码架构
不建议将所有逻辑写在单个循环中,推荐采用三层架构,为后续扩展预留空间:
- 设备通信层(HaplyClient):封装 WebSocket 连接、状态解析、指令发送、连接管理等基础能力
- 力控算法层(HapticController):实现零力、恒力、弹簧、虚拟墙等各类力控算法,与通信层解耦
- 安全管理层(SafetyManager):统一负责状态校验、力限幅、异常检测、安全退出等安全逻辑
该架构可平滑迁移至 ROS2 接入、机械臂联动、仿真环境集成等后续场景。
9.2 基础能力量化验收标准
| 验收维度 | 具体指标 | 合格标准 |
|---|---|---|
| 稳定读取 | 连续运行 10 分钟 | 位置/速度正常更新,无卡顿、无断连,异常拔插有明确处理 |
| 稳定力控 | 零力、恒力、弹簧、虚拟墙四类场景 | 力方向正确、边界清晰、无明显振荡,输出力不超限 |
| 安全退出 | Ctrl+C、断连、拔电源、服务停止 | 均能触发安全逻辑,无残留力,程序不崩溃 |
| 状态感知 | 校准、电源、就绪、占用状态 | 能正确识别并对应控制策略,非就绪状态不输出力 |
总结
Inverse3 基础开发的核心,从来不是「能让设备出力」,而是建立对力反馈系统的完整认知:状态可信、命令稳定、频率可控、力有限幅、异常可退。这不仅是力反馈开发的基础,更是后续机器人遥操作、虚拟装配、手术仿真等高级场景的核心工程素养。
当能够稳定地读取状态、安全地输出力、从容地处理异常时,Inverse3 就不再是一个陌生的外设,而是一台可信赖、可扩展的三自由度力反馈执行器,可作为遥操作主端、力反馈交互终端融入更复杂的机器人系统中。