Skip to main content

概述

本篇实践介绍如何读取 Wuji Hand 2 指尖传感器元数据,并按自描述格式订阅和解析触觉数据。应用场景包括接入不同传感器布局、监控指尖触觉和记录接触数据。 对应的 Python 示例为 3.fingertip_typed.py,C 示例为 3_fingertip.c。 接口清单、自描述格式的字段定义与标定接口见 Wuji Hand 2 指尖触觉。本页说明集成流程、兼容性要求和运行时行为。
当前测试设备不具备指尖触觉传感器,因此本文只覆盖能力判定方法、四条失败路径和接口版本分界。支持设备的数据处理流程以接口定义和产品规格为准。

前置条件

硬件

2.2 的交付形态是触点阵列:拇指 40 触点,其余手指各 34 触点,每触点三轴力加温度,100 Hz 推送。

软件

前序步骤

先确认设备支持该能力,方法见下一节。

数据流

顺序不能颠倒。没有 info 就无法解码 data,帧里没有自描述头。

判定设备是否支持该能力

最可靠的运行时判定是看资源清单,不要靠版本号推断:
实测在不具备的设备上,topics() 里未返回 fingertip 条目。具备的设备会列出五条 fingertip/<finger>/data。 这个判定不需要 try/except,也不依赖硬件或固件版本号的映射关系。

format 契约

info.format 是一个 JSON 字符串,示例把它当唯一真相源,一个字段都不硬编码。关键字段: 字段类型到解包格式的映射,示例写死成一张表并对未知类型直接抛错:
遇到表里没有的类型就抛异常,绝不猜。 猜错一个类型,整帧数据会被解释成看似合理的垃圾。

数据长度自校验

解码前先算期望长度,对不上直接报错:
这条校验能在第一帧就把 info 与 data 版本不匹配的情况暴露出来。

根据 format 读取单位

firmware v2.4.0 及以上版本,每触点的力归一化到传感器满量程:法向轴 0 到 1,切向轴 -1 到 1,超出部分截断。更早的固件按牛顿上报。合力与温度在两者上都是牛顿和摄氏度。 所以接触阈值要按声明的单位选,不能写死:
固件升级之后要重新读 info,解码器才会拿到新的 scale 与 unit。

将触点坐标转换到手模型

positions 与 point_rpy 在传感器模块自身坐标系里,base_xyz 与 base_rpy 给出这个坐标系相对手指 tip_sensor_frame 的位姿。所以触点 i 在手指坐标系里的位置是:
它的力轴旋转是 R(base_rpy) @ R(point_rpy[i])。 合力可以还原成真正的力旋量:力为 R(base_rpy) @ R(aggregate_rpy) @ (fx, fy, fz),作用点为 R(base_rpy) @ aggregate_xyz + base_xyz,对连杆原点的力矩是 p × f。 这三个安装位姿键是一起加进契约的。 示例据此做了一条判定:三个全缺表示固件较早、位置信息不可用,只缺一部分说明元数据本身坏了,直接抛错。缺 aggregate_xyz 的固件不报作用点也不报力矩——在那里猜一个点等于凭空编造力臂。 设备会按自己的左右手上报位姿,同一份代码在左手和右手上都对。

SDK 接口版本兼容性

这是接入时需要确认的兼容性要求。 C 侧同理,wuji_hand_2_get_fingertip_thumb_info(dev, &out) 取代了 wuji_hand_2_get_fingertip_info(dev, finger, &out)。 SDK 不提供兼容适配层。 在 v2026.8.31 上调用新接口:
C 侧则是链接期就失败,找不到被移除的符号。结构体布局没变,所以旧二进制是响亮地失败,而不是悄悄读错数据。 旧接口的参数是整数,传字符串会被绑定层拦下:
0=thumb, 1=index, 2=middle, 3=ring, 4=pinky。
仓库里的示例跟随最新接口。使用旧版 SDK 运行示例时,会在读取 info 的步骤抛出 AttributeError。此错误与设备无关。

设备不支持该能力时的行为

设备信息:firmware_version = 1.3.0,hw_version = HwVersion(major=0, minor=2, patch=0)。 四条路径全部失败,错误来自不同层: 五根手指的 get_fingertip_info 报的是同一条。topics() 里也未返回 fingertip 条目。 注意 Python 对象上有 fingertip_thumb_data、get_fingertip_info、tactile_calibrate、tactile_status 这些方法——方法存在不代表设备支持,SDK 的接口面是按产品定义的,能不能用要看设备的资源清单。

集成步骤

以下以拇指为例,依次连接设备、读取格式、接收数据和释放资源。完整五指读取代码见 Python 示例 和 C 示例。 下文复用 Python 示例 和 C 示例 中的辅助函数和类型:Python 的 fetch_format、make_decoder,以及 C 的 finger_ctx_t、parse_format、on_fingertip_data、snapshot、status_line。这些辅助函数负责解析格式、检查数据帧和显示结果,并非 SDK 接口。

1. 连接指定设备

先按回调订阅实践完成 SDK 初始化和设备连接。多设备环境按目标 SN 选择设备。后续 Python 片段使用已连接的 hand 和 manager,C 片段使用已连接的 dev。

2. 读取拇指格式并准备解码器

读取 info,保存格式摘要,并按 format 描述的字段类型、偏移和比例建立解码器。只有这一步成功,才订阅对应手指。读取失败时跳过该手指,或结束单指程序并断开设备。
fetch_format(hand, 0) 内部调用 hand.fingertip_thumb_info().get()。C 的 parse_format 同时准备后续回调所需的长度、单位和字段信息。两种语言都从格式读取布局,避免写死触点数量或字节偏移。

3. 订阅并处理数据帧

Python 在主循环读取订阅队列,C 由后台回调接收帧。先检查 info_digest 与保存的摘要一致,再解码。摘要为 0 时不解码,摘要变化时重新读取 info 并建立解码器。帧长度必须与格式声明一致。
C 片段沿用 C 示例 的 g_stop、信号处理和 REFRESH_US。on_fingertip_data 检查帧状态、摘要和长度,并在互斥锁保护下复制数据,主线程通过 snapshot 读取。摘要变化时,C 示例 丢弃该帧并显示状态,应用需关闭订阅、重新读取格式后再订阅。

4. 关闭订阅并断开设备

先关闭订阅,等回调工作线程结束,再释放回调上下文和设备。Python 已在上一步的 finally 中处理正常退出、异常和中断。C 的成功路径与失败路径共用以下清理段。

运行与输出

具备该能力时,Python 示例以 100 Hz 原地重绘:每根手指一行状态(合力、温度、接触点数、最强接触点的位置),下面是每个触点的 fx / fy / fz 表格。每轮先排空订阅队列,只显示最新一帧。默认跑 15 秒。 不具备该能力的设备上,实测四条路径全部失败:
以上为实机运行结果,设备固件 1.3.0,硬件版本 0.2.0,SDK v2026.8.31。

注意事项

单根手指读不到 info 是正常情况,不是故障。示例的处理是跳过它继续解码其余手指,只有五根全读不到才停。

重新标定与状态查询

具备该能力的设备上,hand.tactile_calibrate() 把五个指尖重置到全新零基线。C 侧是 wuji_hand_2_tactile_calibrate(dev)。 标定期间传感器表面必须无负载,不能触碰、不能压在任何东西上。标定完用 hand.tactile_status(finger) 查各传感器的型号与标定状态,确认已完成。 joint_diagnostics 流的每帧汇总里带指尖触觉在线位图,可以用来持续监控哪些指尖在线,不用轮询。

扩展用法

降低输出率

100 Hz 五路触点阵列的数据量不小。fingertip/*/data 是速率控制的入口点,可以用订阅句柄的 set_rate() 降频,需要固件 v2.3.0 及以上版本,见 Wuji Hand 2 输出率调节。

固件升级后重读 info

format 里的 scale、unit、安装位姿都可能随固件变。升级之后不重读 info,解码器会按旧契约解析新数据,结果是数值全错但不报错。把读 info 放在每次连接之后,别缓存到磁盘。

仅判断是否接触

不需要每个触点的三轴力时,用合力段的 fx/fy/fz 加一个阈值就够了,不用解每个触点。合力在任何固件上都是牛顿,不受归一化影响。

逐指容错

五根手指各自独立上报 info。写生产代码时按指处理失败,别让一根手指的问题中断整条流水线——示例就是这么改的。

相关内容