你有一堆 BioTac 的 .csv / .h5 / .mat 文件,想做数据标注或清洗。写解析脚本太累,手动标注更累。这篇教程教你用
tlabel一行代码搞定。
你的 BioTac 数据长什么样
BioTac 每次采集产生四种物理信号:
表格
| 信号 | 维度 | 物理含义 |
|---|---|---|
| impedance(阻抗) | 19 电极阵列 | 接触区域形状与形变 |
| PDC(静态压力) | 1 通道 | 法向力大小 |
| PAC(动态压力) | 1 通道(AC) | 微滑移与纹理振动 |
| temperature(温度) | 1 通道 | 热传导 |
你手里的文件可能是 .csv(最常见)、.h5(HDF5)或 .mat(MATLAB),格式各家实验室还不完全一样。
现在问题来了:你想用这些数据做抓取分类、滑移检测、纹理识别,甚至训练基础模型------但你需要的不是原始信号,而是语义标注:
- 这一帧有没有接触?碰到了哪里?
- 力有多大?有没有滑移?
- 当前处于什么操作阶段(接近 / 抓取 / 保持 / 抬起)?
这就是 TLabel 干的事。
3 分钟上手
安装
python
pip install tlabel
如果你的数据是 HDF5 或 MAT 格式,还需要装对应的依赖:
python
# HDF5 格式
pip install h5py
# MATLAB 格式
pip install scipy
CSV 格式开箱即用,不需要额外依赖。
加载你的第一个 BioTac 文件
python
from tlabel.adapters.syntouch import SynTouchBioTacAdapter
adapter = SynTouchBioTacAdapter()
data = adapter.load("your_biotac_data.csv")
# 查看基本信息
print(data.describe())
就这么简单。不管你手里的文件是什么格式,load() 会自动识别:
.csv:自动解析列结构(有表头按表头映射,无表头按 BioTac 标准列序推断).h5:自动发现impedance/pdc/pac/temperature等 dataset,支持子组嵌套.mat:同上,自动匹配变量名
看看标注结果
python
# 每一帧都有语义标注
for frame in data.frames[:5]:
print(f"帧 {frame.frame_idx} | "
f"接触: {frame.schema_v2.contact} | "
f"接触区域: {frame.schema_v2.contact_region} | "
f"力: {frame.schema_v2.force_magnitude} | "
f"滑移: {frame.schema_v2.slip_event} | "
f"阶段: {frame.manipulation_phase}")
输出类似:
python
帧 0 | 接触: False | 接触区域: None | 力: 0.0 | 滑移: False | 阶段: pre_contact
帧 1 | 接触: False | 接触区域: None | 力: 0.0 | 滑移: False | 阶段: pre_contact
帧 10 | 接触: True | 接触区域: distal | 力: 0.3241 | 滑移: False | 阶段: approach
帧 11 | 接触: True | 接触区域: distal | 力: 0.4512 | 滑移: False | 阶段: approach
帧 50 | 接触: True | 接触区域: palmar | 力: 1.2847 | 滑移: True | 阶段: grasp
自动标注了什么
BioTac 适配器能自动从 4 路原始信号推断出 10 个语义维度,不需要你手动标注:
接触相关
- contact:基于 PDC 偏离基线的程度自动判定(前 10 帧作为基线,阈值 = 5σ)
- contact_region :从 19 电极阻抗变化分布推断接触在指尖的位置
distal(指尖顶部)、palmar(指腹)、lateral(侧面)、proximal(近端)
- contact_centroid:用 19 电极的加权质心计算接触中心点(归一化坐标)
力学相关
- force_magnitude:从 PDC 静态压力偏移估算法向力大小
- object_deformation:从 19 电极阻抗总变化量估算物体形变程度
动态相关
- slip_event:从 PAC 动态压力的滑动窗口能量突变检测微滑移
- manipulation_phase :根据接触/滑移序列推断操作阶段
- 自动识别:
pre_contact→approach→grasp/hold→lift→place
- 自动识别:
其他
- temperature:直接透传温度通道
- confidence:每帧标注的置信度(默认 0.85)
原始信号保留
语义标注之外,每帧的 sensor_specific 字段保留原始信号值,方便你回溯:
python
frame = data.frames[50]
print(frame.sensor_specific)
# {'impedance': [...19个值...], 'pdc': 1.2847, 'pac': 0.0234, 'temperature': 26.3}
实用场景
场景 1:快速统计一次抓取的接触情况
python
data = adapter.load("grasp_trial_01.csv")
total_frames = len(data.frames)
contact_frames = sum(1 for f in data.frames if f.schema_v2.contact)
slip_frames = sum(1 for f in data.frames if f.schema_v2.slip_event)
print(f"总帧数: {total_frames}")
print(f"接触帧数: {contact_frames} ({contact_frames/total_frames*100:.1f}%)")
print(f"滑移帧数: {slip_frames} ({slip_frames/total_frames*100:.1f}%)")
场景 2:按操作阶段切分数据
python
# 只取 grasp 阶段的帧
grasp_frames = [f for f in data.frames if f.manipulation_phase == "grasp"]
# 或者按阶段分组
from collections import defaultdict
by_phase = defaultdict(list)
for f in data.frames:
by_phase[f.manipulation_phase].append(f)
for phase, frames in by_phase.items():
print(f"{phase}: {len(frames)} 帧")
场景 3:提取接触区域的分布
python
from collections import Counter
regions = [f.schema_v2.contact_region for f in data.frames
if f.schema_v2.contact and f.schema_v2.contact_region]
print(Counter(regions))
# Counter({'palmar': 120, 'distal': 45, 'lateral': 12})
场景 4:导出为训练数据
python
# 导出为 JSON Lines(每帧一行 JSON,适合下游训练)
import json
with open("annotations.jsonl", "w") as f:
for frame in data.frames:
record = {
"frame_idx": frame.frame_idx,
"timestamp_s": frame.timestamp_s,
"contact": frame.schema_v2.contact,
"contact_region": frame.schema_v2.contact_region,
"contact_centroid": frame.schema_v2.contact_centroid,
"force_magnitude": frame.schema_v2.force_magnitude,
"slip_event": frame.schema_v2.slip_event,
"manipulation_phase": frame.manipulation_phase,
"object_deformation": frame.schema_v2.object_deformation,
"temperature": frame.schema_v2.temperature,
"confidence": frame.confidence,
}
f.write(json.dumps(record) + "\n")
场景 5:批量处理整个数据集
python
from pathlib import Path
data_dir = Path("biotac_dataset/")
all_data = []
for csv_file in sorted(data_dir.glob("*.csv")):
try:
d = adapter.load(str(csv_file))
all_data.append(d)
print(f"✅ {csv_file.name}: {len(d.frames)} 帧")
except Exception as e:
print(f"❌ {csv_file.name}: {e}")
print(f"\n共加载 {len(all_data)} 个 episode")
参数调优
默认的自动检测参数能覆盖大部分场景。如果你的数据有特殊需求,可以手动调:
python
# 自定义采样率(BioTac 默认 100Hz)
data = adapter.load("data.csv", sample_rate=200.0)
# 调整接触判定阈值(默认自动计算 = 基线 σ × 5)
# 值越小 → 越灵敏,容易把噪声判为接触
# 值越大 → 越保守,可能漏掉轻触
data = adapter.load("data.csv", contact_threshold=0.5)
# 调整基线帧数(默认用前 10 帧)
# 如果前几帧已经有接触,需要增大这个值
data = adapter.load("data.csv", baseline_frames=20)
CSV 格式说明
有表头的 CSV
表头名自动匹配(不区分大小写):
表格
| 阻抗 | 静态压力 | 动态压力 | 温度 |
|---|---|---|---|
e1-e19 或 electrode_0-electrode_18 |
pdc / static_pressure |
pac / dynamic_pressure |
tac / temperature / tdc |
无表头的 CSV
当 CSV 没有列名时,适配器按 BioTac 标准列序推断:
- 前 19 列 → 电极阻抗
- 第 20 列 → PAC(动态压力)
- 第 21 列 → PDC(静态压力)
- 第 22 列 → TAC(温度)
- 第 23 列 → TDC(可选)
如果你的 CSV 列序不同,建议先加一行表头。
命令行快速检查
不想写代码?CLI 也能用:
python
# 查看 BioTac 适配器的能力声明
tlabel info syntouch
# 验证一个文件是否符合 Schema V2
tlabel validate your_data.csv
# 列出所有支持的适配器
tlabel list
标注结果能干什么
TLabel 给你的是 结构化的语义标注,不是原始信号。拿到标注后:
- 训练分类模型 :用
contact+slip_event+manipulation_phase做标签 - 跨传感器对比:BioTac 的标注可以直接和其他传感器(GelSight、PaXini 等)的数据对齐比较,因为共享同一套 Schema V2
- 数据质量评估 :用
tlabel的质量评分功能检查你的数据集覆盖度 - 喂给基础模型:导出 FTP-1 Zarr 格式,直接用于具身智能基础模型训练
python
# 质量评估
from tlabel.quality import quality_score
score = quality_score(data)
print(score)
# {'physical_consistency': 0.92, 'temporal_smoothness': 0.87,
# 'completeness': 0.71, 'coverage': 0.65, 'overall': 0.79}
# 导出 FTP-1 Zarr 格式
data.export_ftp1("output.zarr")
一句话总结
BioTac 数据 → tlabel.load() → 10 维语义标注,自动推断接触/力/滑移/阶段/温度,省去手写解析脚本的活。标注结果结构统一,可以直接用于训练、跨传感器对比、质量评估。
python
pip install tlabel
GitHub: github.com/liesliy/tlabel · PyPI: pypi.org/project/tlabel
有问题?GitHub Issues 提需求,欢迎贡献更多传感器适配器。