跳到主要内容

Smart/T-Piezo Python SDK

tactile_sdk 是 Smart/T-Piezo 压阻触觉皮肤的 Python 开发包,基于 Modbus RTU 协议通过串口与传感器通信,封装了 60 点压力数据采集、设备配置、传感器标定和动态归零等接口,实测最高采样率约 1480 Hz。

本文档基于 Synria-Robotics/Electronic-Skin-ML v0.1 版本。

1. 介绍

1.1 核心能力

核心能力
  • 基于 Modbus RTU 协议,通过串口与 Smart/T-Piezo 传感器通信
  • 提供 TactilePressureSDK 门面类作为推荐入口,封装 DeviceAPI / ConfigAPI / PressureAPI / CalibrationAPI
  • 支持 60 点触觉压力实时采集,read_fast() 实测最高约 1480 Hz
  • 支持标定值(mN)与 ADC 原始值两种输出模式
  • 支持动态归零:软件层逐点基线补偿
  • 支持传感器标定:最多 11 个分段线性拟合点,支持单点标定和全部标定
  • 支持设备参数读写:地址、采样频率、AD 屏蔽值、点面积等
  • 提供完整异常体系(TactileSdkError 及子类)

1.2 SDK 目录结构

官方仓库 v0.1 的核心结构如下:

Electronic-Skin-ML/
├── tactile_sdk/ # SDK 主包
│ ├── __init__.py # 公开接口出口
│ ├── client.py # 门面层:TactilePressureSDK
│ ├── exceptions.py # 横切层:统一异常类型
│ ├── models.py # 横切层:业务数据模型 (dataclass)
│ ├── api/ # API 层:按业务领域拆分
│ │ ├── base.py # BaseAPI:持有 modbus + 共享地址
│ │ ├── device_api.py # DeviceAPI:设备信息读写、地址管理
│ │ ├── config_api.py # ConfigAPI:传感器工作参数配置
│ │ ├── pressure_api.py # PressureAPI:压力数据读取
│ │ └── calibration_api.py # CalibrationAPI:标定工作流
│ ├── protocol/ # 协议层:Modbus RTU 帧构建与解析
│ │ ├── constants.py # 功能码、寄存器地址、枚举常量
│ │ ├── crc16.py # CRC16 算法
│ │ └── modbus_rtu.py # 帧构建/发送/接收/CRC 校验/解析
│ └── transport/ # 传输层:串口物理 I/O
│ └── serial_transport.py # pyserial 封装,字节级 I/O
├── examples/ # 9 个完整示例脚本
│ ├── 01_demo_quickstart.py # 连接验证与设备信息读取
│ ├── 02_demo_calibration.py # 手动输入标定数据
│ ├── 03_demo_configuration.py # 设备参数配置
│ ├── 04_demo_read_pressure.py # 高速连续读取(200 Hz)
│ ├── 05_demo_record_pressure.py# 数据记录到 CSV
│ ├── 06_demo_recover_calibration.py # 恢复出厂标定
│ ├── 07_demo_test_fps.py # 最大采样率压测
│ ├── 08_demo_zero_baseline.py # 手动动态归零
│ └── 09_demo_baseline_initialization.py # 重置动态归零
├── requirements.txt
└── actual.moduluscali.moduluscali.csv # 出厂标定数据备份

2. 安装与准备

2.1 环境要求

  • Python 3.7 及以上版本
  • USB 转串口适配器(推荐 FTDI 芯片,避免 CH340 延迟问题)
  • 已上电的 Smart/T-Piezo 传感器

2.2 安装步骤

克隆指定版本源码:

git clone https://github.com/Synria-Robotics/Electronic-Skin-ML.git -b v0.1
cd Electronic-Skin-ML

安装依赖(仅需 pyserial):

pip install -r requirements.txt

2.3 串口连接检查

平台典型串口名
WindowsCOM3COM6 等(设备管理器查看)
Linux/dev/ttyUSB0/dev/ttyACM0
macOS/dev/tty.usbserial-*

Linux 如遇权限问题,可执行:

sudo usermod -a -G dialout $USER

重新登录后再访问串口。

3. 公共 API 概览

tactile_sdk 在包入口导出了以下常用对象:

3.1 推荐入口(门面层)

名称说明
TactilePressureSDK门面类,封装了 DeviceAPI / ConfigAPI / PressureAPI / CalibrationAPI,推荐作为首选入口

3.2 数据模型

名称说明
DeviceInfo设备身份信息,包含型号、协议编号/版本、固件版本
PressureFrame一帧压力数据,包含 60 点数值列表、时间戳、总压力
FittingPoint标定拟合点,包含编号、已知压力值(mN)和 ADC 采样值
CalibrationStatus当前标定状态:模式、压力点编号、拟合点编号
CalibrationMode标定模式枚举:SINGLE_POINT(100)/ ALL_POINTS(101)

3.3 异常体系

名称说明
TactileSdkError基类,可一网打尽所有 SDK 异常
DeviceConnectionError串口打不开 / 意外断开
CommunicationError超时 / CRC 失败 / 帧不完整
ProtocolError功能码异常 / Modbus 异常响应码
ValidationError参数越界(地址/频率/压力值等)
CalibrationError标定操作失败(通常包装上述异常)

4. TactilePressureSDK 门面 API

TactilePressureSDK 是门面类,推荐所有新代码使用此入口

4.1 构造参数

TactilePressureSDK(
port, # "COM6" 或 "/dev/ttyUSB0"
*,
slave_address=1, # Modbus 从设备地址(1–247),默认 1
baudrate=4_000_000, # 波特率,默认 4,000,000
timeout=1.0, # 读超时秒数,默认 1.0
send_wait_secs=0.005, # 发送后等待响应的延迟 [s],默认 0.005
)

4.2 连接管理

sdk.connect()        # 打开串口(已打开时为空操作)
sdk.disconnect() # 关闭串口
sdk.is_connected # 属性 bool,串口是否已打开

# 推荐用上下文管理器(自动 connect / disconnect)
with TactilePressureSDK("COM6") as sdk:
...

4.3 .device — DeviceAPI

方法说明
get_info()一次读取全部设备身份信息,返回 DeviceInfo
get_model()读取设备型号,如 "ST-00-01"
get_protocol_number()读取协议编号
get_protocol_version()读取协议版本
get_app_version()读取固件 App 版本
get_address()从寄存器 0x0001 读取当前 Modbus 地址
set_address(new_addr, *, use_broadcast=True)修改设备 Modbus 地址;广播模式下 SDK 内所有 API 地址同步更新

4.4 .config — ConfigAPI

方法说明
get/set_pressure_value_type(type)输出类型:0 = ADC 原始值,1 = 标定后压力值(mN)
get/set_ad_mask_value(value)AD 屏蔽阈值,低于此值输出 0(范围 0–65535)
get/set_auto_upload_flag(enable)主动上传使能(设备周期性推送,无需主动轮询)
get/set_auto_upload_frequency(freq)主动上传频率(50–200 Hz)
get_pressure_point_count()压力点总数(只读,典型值 60)
get/set_sensor_point_area(area_mm2)单点面积(0–6553.5 mm²,精度 0.1 mm²)
get/set_auto_zero_enable(enable)上电自动归零使能(只写,重启后生效)
trigger_dynamic_zero()立即将当前压力输出归零(建议无负载时调用)
reset_dynamic_zero()撤销动态归零,恢复出厂零点

4.5 .pressure — PressureAPI

SDK 提供两条读取路径:

方法说明
read_all()标准路径,返回 PressureFrame;失败抛 CommunicationError
read_fast()高频快速路径,返回 List[int];失败返回 None,不抛异常

4.6 .calibration — CalibrationAPI

方法说明
get/set_mode(mode)标定模式:CalibrationMode.SINGLE_POINT(100)/ ALL_POINTS(101)
get/set_pressure_point(point)选定要标定的压力点编号(单点模式用)
get/set_fitting_point(point)选定拟合点编号(1–11)
get_fitting_point_ad()读取当前拟合点的 ADC 值
set_fitting_point_pressure(pressure_mn)设置当前拟合点对应的已知压力值(mN)
calibrate(*, use_sample=True, ad_value=None)执行标定采样
get_status()读取当前标定状态,返回 CalibrationStatus
clear()清除所有标定,恢复出厂状态(不可逆

4.7 快速开始示例

from tactile_sdk import TactilePressureSDK

with TactilePressureSDK("COM6", slave_address=1) as sdk:
# 读取设备信息
info = sdk.device.get_info()
print(f"设备型号: {info.device_model}") # "ST-00-01"
print(f"固件版本: {info.app_version}") # "v1.0.1"
print(f"压力点数: {sdk.config.get_pressure_point_count()}") # 60

# 切换为标定值输出(mN)
sdk.config.set_pressure_value_type(1)

# 读取一帧
frame = sdk.pressure.read_all()
print(f"各点压力: {frame.values}")
print(f"总压力: {frame.total_pressure} mN")

5. 示例脚本(Demos)

所有示例位于 examples/,串口号统一设为 COM6,运行前请根据实际情况修改顶部的 PORT 变量,SLAVE_ADDRESS 须与设备拨码开关一致(出厂默认为 1)。

cd examples
python 01_demo_quickstart.py

5.1 01_demo_quickstart.py

连接设备,读取设备信息和基本配置寄存器,用于验证串口通信是否正常。输出内容:设备型号、协议编号/版本、固件版本、压力点数、主动上传频率、压力值类型等。

5.2 02_demo_calibration.py

手动输入标定数据。交互式输入,格式为 压力(mN) AD值,支持 1–11 个拟合点,输入完毕确认后以全部标定模式写入设备。

python 02_demo_calibration.py
# 标定点 1: 0 10
# 标定点 2: 100 559
# 标定点 3: 500 1729
# 标定点 4: ← 直接回车结束

5.3 03_demo_configuration.py

读取并修改设备配置,包括压力值类型、AD 屏蔽值、Modbus 地址(含交互确认)。

5.4 04_demo_read_pressure.py

以 200 Hz 固定目标频率持续采样,每帧打印 60 点压力值,每秒输出一行性能统计:

>>> 统计: 实际采样率=198.3Hz | 成功=198 | 失败=0 | 错误率=0.00%

Ctrl+C 停止。

核心代码:

import time
from tactile_sdk import TactilePressureSDK

TARGET_HZ = 200
interval = 1.0 / TARGET_HZ
next_t = time.perf_counter()

with TactilePressureSDK("COM6") as sdk:
sdk.config.set_pressure_value_type(1)
while True:
now = time.perf_counter()
if now < next_t:
time.sleep(next_t - now)
values = sdk.pressure.read_fast()
if values is not None:
process(values) # 你的处理逻辑
next_t += interval

5.5 05_demo_record_pressure.py

交互式配置采样率(10 / 50 / 100 / 200 Hz 或自定义)和时长,将压力数据保存为 CSV 文件。

CSV 格式:

时间戳, 相对时间(秒), 压力点1, 压力点2, ..., 压力点60
1746000000.123, 0.000, 0, 128, 256, ...

5.6 06_demo_recover_calibration.py

恢复出厂标定。向固件寄存器 0x0070 写入 119,由设备自动还原出厂烧录参数,兼容任意批次/型号。含安全确认提示。

注意

此操作不可逆,运行后将覆盖当前所有自定义标定数据。

5.7 07_demo_test_fps.py

最大采样率压测。以全速无限循环调用 read_fast(),不做任何限速,每秒打印性能统计:

实际频率: 1480.2 Hz | 点数: 60 | 成功: 1480 | 失败: 0 | 错误率: 0.00%

5.8 08_demo_zero_baseline.py

手动动态归零。触发后 SDK 采集当前 60 点存为软件基线,后续所有读取自动逐点扣减(output[i] = max(0, raw[i] - baseline[i]))。建议传感器表面无负载时执行。

备注

软件基线仅在当次 SDK 连接生命周期内有效,断开重连后自动清除。

5.9 09_demo_baseline_initialization.py

重置动态归零。清除软件基线,压力值恢复为上电时的硬件零点状态。

6. 获取传感器运行参数

6.1 实时压力数据

from tactile_sdk import TactilePressureSDK

with TactilePressureSDK("COM6") as sdk:
sdk.config.set_pressure_value_type(1) # 切换标定值模式

# 标准读取(含错误处理)
frame = sdk.pressure.read_all()
print(f"点数 = {frame.point_count}")
print(f"各点压力 = {frame.values}") # List[int], 长度 60
print(f"总压力 = {frame.total_pressure} mN")
print(f"时间戳 = {frame.timestamp:.3f}")

# 高频读取(热循环专用,失败返回 None)
values = sdk.pressure.read_fast()
if values is not None:
print(values)

6.2 读取设备寄存器参数

from tactile_sdk import TactilePressureSDK

with TactilePressureSDK("COM6") as sdk:
info = sdk.device.get_info()
print(f"设备型号: {info.device_model}")
print(f"协议编号: {info.protocol_number}")
print(f"协议版本: {info.protocol_version}")
print(f"固件版本: {info.app_version}")

print(f"Modbus地址: {sdk.device.get_address()}")
print(f"压力点总数: {sdk.config.get_pressure_point_count()}")
print(f"输出类型: {sdk.config.get_pressure_value_type()}") # 0=AD, 1=mN
print(f"AD屏蔽值: {sdk.config.get_ad_mask_value()}")
print(f"点面积: {sdk.config.get_sensor_point_area()} mm²")

7. 标定操作

每个压力点支持最多 11 个分段线性拟合点(索引 1–11),建立 ADC 原始值 → 实际压力(mN)的映射关系。

7.1 全部标定(推荐)

对所有 60 个压力点统一应用同一组拟合曲线:

from tactile_sdk import TactilePressureSDK, CalibrationMode

with TactilePressureSDK("COM6") as sdk:
sdk.calibration.set_mode(CalibrationMode.ALL_POINTS)

fitting_plan = [
(1, 0), # 拟合点1:空载 0 mN
(2, 200), # 拟合点2:施加 200 mN
(3, 500),
(4, 1000),
]
for fitting_point, pressure_mn in fitting_plan:
sdk.calibration.set_fitting_point(fitting_point)
sdk.calibration.set_fitting_point_pressure(pressure_mn)
input(f"请施加 {pressure_mn} mN 后按 Enter 采样...")
sdk.calibration.calibrate(use_sample=True)
ad = sdk.calibration.get_fitting_point_ad()
print(f"拟合点 {fitting_point}: {pressure_mn} mN → AD={ad}")

7.2 单点标定

仅标定指定压力点:

with TactilePressureSDK("COM6") as sdk:
sdk.calibration.set_mode(CalibrationMode.SINGLE_POINT)
sdk.calibration.set_pressure_point(5) # 选定压力点 5
sdk.calibration.set_fitting_point(1)
sdk.calibration.set_fitting_point_pressure(0)
sdk.calibration.calibrate()

7.3 离线标定(手动指定 AD 值)

sdk.calibration.set_fitting_point(2)
sdk.calibration.set_fitting_point_pressure(1000)
sdk.calibration.calibrate(ad_value=2284) # 直接写入历史 AD 值
提示

如需恢复出厂标定,运行 06_demo_recover_calibration.py,由固件自动还原匹配本设备的出厂参数,无需知道具体参数值。

8. 底层 API 速查

信息

以下为各 API 子类方法汇总,供需要精细控制的高级用户参考。普通用户推荐直接使用门面层(见第 4 节)。

sdk.device

方法作用
get_info()读取完整设备身份信息(4 次 0x41 请求)
get_address()读取当前 Modbus 地址
set_address(addr, use_broadcast)修改 Modbus 地址(默认广播,SDK 内部地址同步)

sdk.config

方法作用
get/set_pressure_value_type(type)ADC 原始值(0)/ 标定值 mN(1)
get/set_ad_mask_value(value)AD 屏蔽阈值
get/set_auto_upload_flag(enable)主动上传使能
get/set_auto_upload_frequency(freq)主动上传频率(50–200 Hz)
get_pressure_point_count()压力点总数(只读)
get/set_sensor_point_area(area_mm2)单点面积
trigger_dynamic_zero()触发动态归零
reset_dynamic_zero()重置动态归零

sdk.pressure

方法作用
read_all()标准读取,返回 PressureFrame,失败抛异常
read_fast()高频读取,返回 List[int]None

sdk.calibration

方法作用
get/set_mode(mode)标定模式
get/set_pressure_point(point)目标压力点编号
get/set_fitting_point(point)目标拟合点编号(1–11)
get_fitting_point_ad()读取当前拟合点 ADC 值
set_fitting_point_pressure(mn)设置当前拟合点已知压力值
calibrate(use_sample, ad_value)执行标定
get_status()读取当前标定状态
clear()清除所有标定(不可逆)

9. 硬件通信参数

参数
通信协议Modbus RTU
波特率4,000,000 bps
数据位8
校验位
停止位1
从设备地址范围1–247
广播地址0(修改地址时使用,设备不返回响应)
压力点数量60
压力数据格式uint16 × 60,小端序(每帧 120 字节数据域)
实测最大采样率~1480 Hz(read_fast 全速无限制)
推荐采样率100–200 Hz

10. 故障排查

现象 / 异常排查方向
DeviceConnectionError / 串口打不开检查串口号;确认没有其他程序(串口助手等)占用该串口
CommunicationError / 超时或帧错误检查波特率(默认 4,000,000);检查线缆连接;确认 slave_address 与拨码开关一致
ProtocolError / 功能码异常通常为固件版本不匹配,联系技术支持
ValidationError / 参数越界检查传入参数范围,例如地址 1–247,频率 50–200 Hz
压力值全为 01. 确认 set_pressure_value_type(1) 已切换为标定值模式;2. 检查 get_ad_mask_value() 是否过高;3. 运行 06_demo_recover_calibration.py 恢复出厂标定
实际采样率达不到目标1. 改用 read_fast();2. 减少循环内打印/写文件等 I/O;3. 确认波特率为 4,000,000;4. 使用 FTDI 芯片的适配器;5. 适当减小 send_wait_secs
get_auto_zero_enable() 返回 None该寄存器(0x0011)在部分固件为只写,SDK 捕获异常后返回 None,属正常行为
修改地址后连不上set_address() 会同步更新 SDK 内部地址,无需重建实例;若已断开,用新地址重新连接即可