PSI 手套 Python SDK 使用手册
ψ-SynGlove Air Python SDK 完整文档。
📋 目录
1. 硬件安装方法说明
本文适用于 ψ-SynGlove Air(Air Hand V2):22 路关节 ADC 采集,五指可选配 LRA 线性马达 触觉反馈。通信协议与 SDK Modbus 章节一致(读关节、写 0xB0 LRA)。
SDK 源码仓库路径:psi-air-glove-SDK/psi-air-glove-SDK/(含 python_sdk、cpp_sdk、ros2_sdk)。
1.1 硬件清单
- PSI 数据手套(左手/右手)
- USB 数据线
1.2 硬件连接步骤
┌────────────────┐ ┌─────────────┐
│ PSI 数据手套 │ ──────── USB ───────→ │ 计算机 │
│ (左手/右手) │ (虚拟串口通信) │ (运行SDK) │
└────────────────┘ └─────────────┘连接步骤:
- 连接手套:使用 USB 数据线将数据手套直接连接到计算机 USB 接口
- 手套供电:手套通过 USB 接口供电
- 虚拟串口:计算机会自动创建虚拟串口设备用于通信
- 确认设备:
- Linux: 运行
ls /dev/ttyUSB* /dev/ttyACM*查看设备(通常为/dev/ttyACM0) - Windows: 打开设备管理器查看 COM 口(如 COM31)
- macOS: 运行
ls /dev/tty.usbmodem*或ls /dev/cu.usbmodem*
- Linux: 运行
注意事项:
- 手套使用 USB 供电,无需额外电源适配器
- 首次连接时,操作系统会自动安装 USB CDC 驱动
1.3 串口权限设置(Linux)
# 将当前用户添加到 dialout 组
sudo usermod -a -G dialout $USER
# 注销后重新登录,或使用以下命令立即生效
newgrp dialout
# 验证权限
ls -l /dev/ttyACM02. SDK安装和配置方法
本文档对应 ψ-SynGlove Air Python SDK,源码位于:
psi-air-glove-SDK/psi-air-glove-SDK/python_sdk/
安装后通过 import psi_glove_sdk 使用,当前版本 0.1.5(以 psi_glove_sdk/VERSION 为准)。
2.1 系统要求
| 项目 | 要求 |
|---|---|
| Python | 3.7+(离线 wheel 推荐 3.10) |
| 操作系统 | Linux / Windows / macOS |
| 基础依赖 | pyserial >= 3.5 |
| 可选依赖 | numpy(平滑加速)、mujoco / ruamel.yaml(指尖 FK 与可视化) |
2.2 从源码安装
# 进入 Python SDK 目录
cd psi-air-glove-SDK/psi-air-glove-SDK/python_sdk
# 可编辑安装(自动安装 requirements.txt 中的依赖)
pip install -e .
# 验证
python -c "import psi_glove_sdk; print('OK', psi_glove_sdk.__version__)"开发态资源路径(不在 psi_glove_sdk/resources/ 源码副本中):
- 默认配置:
python_sdk/configs/ - URDF 模型:仓库内
SynGlove_Air_URDF/(与python_sdk同级)
2.3 离线Wheel包安装
适用于目标机无法访问 PyPI、需一次性打包配置与 URDF 的场景。
cd psi-air-glove-SDK/psi-air-glove-SDK/python_sdk
# 默认按本机架构生成 manylinux 标签(x86_64 / aarch64)
python scripts/package_offline_wheel.py
# 指定 Python 标签与平台(示例)
python scripts/package_offline_wheel.py --python-tag cp310 --plat-name manylinux_2_17_x86_64
# 安装
pip install ./build/dist/psi_air_glove-*.whl说明:
- Wheel 包名:
psi-air-glove(import 名仍为psi_glove_sdk)。 - 构建时会把
configs/与SynGlove_Air_URDF/打入 wheel 内的psi_glove_sdk/resources/。 - 平台标签须与目标 Linux 匹配,否则
pip install会拒绝安装。
2.3.1 使用已有离线包安装
若已拿到 psi_air_glove-<version>-cp<py>-none-linux_<arch>.whl(例如 psi_air_glove-0.1.5-cp310-none-linux_x86_64.whl),无需在目标机上重新执行 package_offline_wheel.py,按下列步骤安装即可。
1. 确认环境匹配
| 检查项 | 说明 |
|---|---|
| Python 版本 | 文件名中的 cp310 表示需 Python 3.10;cp311 对应 3.11,以此类推 |
| 操作系统 | 当前 wheel 为 Linux x86_64 / aarch64 manylinux 标签,不支持 Windows / macOS 直接安装 |
| 架构 | linux_x86_64 与 aarch64 不可混用,须与目标机 uname -m 一致 |
2. 安装
# 进入 wheel 所在目录(路径按实际修改)
cd /path/to/dist
# 建议在虚拟环境中安装(可选)
python3 -m venv .venv
source .venv/bin/activate
# 安装离线包(将文件名换成你手里的 wheel)
python3 -m pip install ./psi_air_glove-0.1.5-cp310-none-linux_x86_64.whl
# 若曾装过旧版,可强制覆盖
# python3 -m pip install --force-reinstall ./psi_air_glove-0.1.5-cp310-none-linux_x86_64.whl3. 验证安装
python3 -c "import psi_glove_sdk; print('OK', psi_glove_sdk.__version__)"
python3 -c "
from psi_glove_sdk.config_loader import get_resources_root, get_synglove_urdf_root
print('resources:', get_resources_root())
print('urdf_root:', get_synglove_urdf_root())
"get_resources_root() 非 None 且 urdf_root 下存在 SynGlove_Air_URDF/,说明配置与 URDF 已随 wheel 安装完整。
4. 指尖位姿 / MuJoCo 可视化(可选)
离线 wheel 仅包含 pyserial 与包内 resources;运行 test_fingertip_visualizer.py 或 FingertipPoseCalculator 还需额外安装:
pip install mujoco numpy ruamel.yaml安装完成后即可运行 examples/ 下示例(见 §3 例程)。
2.4 可配置参数
SerialInterface
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
port | str | 必填 | 串口路径,如/dev/ttyACM0、COM3 |
baudrate | int | 115200 | 波特率,常用115200、500000、921600 |
timeout | float | 0.01 | 读超时(秒) |
auto_connect | bool | False | 构造时是否自动连接 |
mock | bool | False | 模拟模式(无硬件测试) |
LRA 连续下发时,写超时默认放宽为 max(1s, 读超时×10),减轻 Write timeout。
PSIGloveController
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
communication_interface | CommunicationInterface | 必填 | 如SerialInterface 实例 |
smoothing_window_size | int | 10 | 移动平均窗口;越大越平滑、延迟越高 |
adc_calibration | ADCCalibrationParams | 内置默认 | 可选 ADC 三次多项式校准 |
2.5 典型配置示例
from psi_glove_sdk import PSIGloveController, SerialInterface
serial = SerialInterface(
port="/dev/ttyACM0",
baudrate=115200,
timeout=0.006,
)
controller = PSIGloveController(serial, smoothing_window_size=10)
if not controller.connect():
raise RuntimeError("连接失败")3. 例程编译和调用方法
SDK 提供四个示例程序,位于 psi-air-glove-SDK/psi-air-glove-SDK/python_sdk/examples/ 目录。
3.1 例程列表
| 例程名称 | 文件 | 功能说明 |
|---|---|---|
| 基础用法 | basic_usage.py | 演示连接、读取 22 路关节数据、断开连接 |
| 高级用法 | advanced_usage.py | 归一化与角度换算、统计信息、CSV 数据记录 |
| LRA触觉反馈 | lra_play_example.py | 线性马达波形与振幅控制(Modbus0xB0) |
| 指尖可视化 | test_fingertip_visualizer.py | MuJoCo 实时显示指尖位姿与坐标系 |
3.2 例程运行方法
运行前建议已在 python_sdk 目录执行 pip install -e .。
3.2.1 基础用法示例
cd psi-air-glove-SDK/psi-air-glove-SDK/python_sdk/examples
# 运行基础示例(指定串口)
python3 basic_usage.py /dev/ttyACM0
# 自定义波特率
python3 basic_usage.py /dev/ttyACM0 500000
# Windows 系统
python basic_usage.py COM31输出示例:
==================================================
PSI Glove SDK - 基础使用示例
==================================================
串口: /dev/ttyACM0
波特率: 115200
==================================================
[INFO] 正在连接到设备...
[INFO] 连接成功!
[INFO] 开始读取数据 (按Ctrl+C退出)...
--- 帧 #0 ---
拇指: 2048, 1856, 2304, 1792, 2176, 1920
食指: 1920, 2240, 1664, 2112
中指: 2304, 1856, 2048, 1792
无名指: 1920, 2176, 1664, 2048
小指: 2240, 1856, 2304, 1920
--- 帧 #10 ---
拇指: 2052, 1860, 2308, 1796, 2180, 1924
...拇指为 6 路关节,其余四指各 4 路;数值为 12 位 ADC(0–4095)。按 Ctrl+C 退出后打印帧率统计。
3.2.2 高级用法示例
# 运行高级示例
python3 advanced_usage.py /dev/ttyACM0
# 自定义波特率
python3 advanced_usage.py /dev/ttyACM0 500000
# 启用 CSV 数据记录(第三个参数为 --log)
python3 advanced_usage.py /dev/ttyACM0 115200 --log输出示例:
==================================================
PSI Glove SDK - 高级使用示例
==================================================
串口: /dev/ttyACM0
波特率: 115200
数据记录: 启用
==================================================
[INFO] 正在连接...
[INFO] 连接成功!
--- 帧 #0 ---
拇指关节角度:
关节 0: 45.2° (归一化: 0.512, 原始: 2048)
关节 1: 38.1° (归一化: 0.431, 原始: 1856)
...
==================================================
统计信息 (拇指指尖关节):
样本数: 1200 | 最小: 1800 | 最大: 2300 | 平均: 2050.3
==================================================启用 --log 时,会在当前目录生成 psi_glove_data_YYYYMMDD_HHMMSS.csv。
3.2.3 LRA 触觉示例
python3 lra_play_example.py COM3 115200
python3 lra_play_example.py /dev/ttyACM0 921600可选参数:--slave(Modbus 从机地址)、--step-sec(每档保持时间)、--amp-max(振幅上限,默认 64)。
示例逻辑:拇指出厂波形,振幅从 1 递增到 amp_max;mode=0 关闭该指马达。
3.2.4 指尖可视化示例
依赖:mujoco、numpy、ruamel.yaml,以及 URDF(开发态在 SynGlove_Air_URDF/,离线 wheel 在 psi_glove_sdk/resources/)。
pip install mujoco numpy ruamel.yaml
python3 test_fingertip_visualizer.py -p /dev/ttyACM0 -b 115200 -H right启动 MuJoCo 窗口,实时显示五指指尖坐标系;终端周期性打印 URDF 关节角与指尖位姿矩阵。
效果展示:

3.3 关节数据说明(22 路)
StatusMessage 包含 22 个关节 ADC 值(12 位,0–4095):
| 手指 | 关节数 | joints 索引 | 属性访问 |
|---|---|---|---|
| 拇指 | 6 | 0–5 | status.thumb |
| 食指 | 4 | 6–9 | status.index |
| 中指 | 4 | 10–13 | status.middle |
| 无名指 | 4 | 14–17 | status.ring |
| 小指 | 4 | 18–21 | status.pinky |
拇指 6 路顺序:tip, mid, back, back2, side, rotate。其余四指:tip, mid, back, side。
4. SDK接口调用说明
4.1 核心类和方法
4.1.1 SerialInterface 类
串口通信接口类,处理底层 Modbus RTU 硬件通信。
from psi_glove_sdk import SerialInterface
# 创建串口接口
serial = SerialInterface(
port="/dev/ttyACM0", # 串口路径(Linux: /dev/ttyACM0,Windows: COM3)
baudrate=115200, # 波特率,常用 115200 / 500000 / 921600
timeout=0.01, # 读超时(秒)
auto_connect=False, # 是否在构造时自动连接
mock=False, # 模拟模式(无真实硬件,用于测试)
write_timeout=None, # 写超时;默认 None 表示 max(1.0, timeout×10)
)| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
port | str | 必填 | 串口设备路径 |
baudrate | int | 115200 | 通信波特率 |
timeout | float | 0.01 | 读超时(秒) |
auto_connect | bool | False | 构造时是否自动connect() |
mock | bool | False | 模拟模式 |
write_timeout | float| None | None | 写超时;LRA 连续下发时建议保持默认 |
4.1.2 PSIGloveController 类
主控制器类,管理连接、Modbus 读关节、移动平均平滑、LRA 触觉下发。
from psi_glove_sdk import PSIGloveController, ADCCalibrationParams
# 创建控制器
controller = PSIGloveController(
communication_interface=serial, # 通信接口实例
smoothing_window_size=10, # 平滑窗口(样本数)
adc_calibration=ADCCalibrationParams() # 可选 ADC 校准,默认内置参数
)核心方法:
| 方法名称 | 返回类型 | 功能说明 |
|---|---|---|
connect() | bool | 连接设备,成功返回True |
disconnect() | None | 断开设备连接 |
is_connected() | bool | 检查是否已连接 |
loop() | Optional[StatusMessage] | 读取关节数据并更新缓存,失败返回None |
read_joint_positions() | Optional[StatusMessage] | 仅读取一帧,不经过loop() 的缓存语义 |
get_last_status() | Optional[StatusMessage] | 获取最后一次成功读取的数据 |
play_lra(modes, amplitudes, slave_id=1) | bool | LRA 线性马达控制(Modbus 写0xB0) |
4.2 读取主手数据的完整流程
#!/usr/bin/env python3
from psi_glove_sdk import PSIGloveController, SerialInterface, StatusMessage
import time
# 步骤 1: 创建串口接口
serial = SerialInterface(
port="/dev/ttyACM0",
baudrate=115200,
timeout=0.006,
)
# 步骤 2: 创建控制器
controller = PSIGloveController(
communication_interface=serial,
smoothing_window_size=10,
)
# 步骤 3: 连接设备
if not controller.connect():
print("错误: 无法连接到设备")
exit(1)
print("连接成功!")
# 步骤 4: 循环读取数据
try:
while True:
# 读取数据(自动 Modbus 解析 + 平滑)
status: StatusMessage = controller.loop()
if status:
print(f"拇指关节 (6): {status.thumb}")
print(f"食指关节 (4): {status.index}")
print(f"中指关节 (4): {status.middle}")
print(f"无名指关节 (4): {status.ring}")
print(f"小指关节 (4): {status.pinky}")
# 22 路关节扁平列表
all_joints = status.to_list()
print(f"所有关节 (22个): {all_joints}")
else:
last_status = controller.get_last_status()
if last_status:
print("读取失败,使用缓存数据")
time.sleep(0.01) # 约 100 Hz
except KeyboardInterrupt:
print("\n用户中断")
finally:
controller.disconnect()
print("已断开连接")4.3 数据格式和单位
StatusMessage 数据结构
Air Hand V2 提供 22 路关节 ADC。StatusMessage 以 joints 为主字段,并通过属性访问各指数据:
from dataclasses import dataclass
from typing import List
@dataclass
class StatusMessage:
joints: List[int] # 22 个关节 ADC,顺序见下表
@property
def thumb(self) -> List[int]: ... # joints[0:6],6 路
@property
def index(self) -> List[int]: ... # joints[6:10]
@property
def middle(self) -> List[int]: ... # joints[10:14]
@property
def ring(self) -> List[int]: ... # joints[14:18]
@property
def pinky(self) -> List[int]: ... # joints[18:22]
def to_list(self) -> List[int]:
"""返回 22 个关节值的列表"""
return list(self.joints)
def to_dict(self) -> dict:
"""返回含 joints 与各指属性的字典"""
...关节索引映射
| 手指 | 关节数量 | joints 索引 | 访问方式 | 顺序说明 |
|---|---|---|---|---|
| 拇指 | 6 | 0–5 | status.thumb | tip, mid, back, back2, side, rotate |
| 食指 | 4 | 6–9 | status.index | tip, mid, back, side |
| 中指 | 4 | 10–13 | status.middle | tip, mid, back, side |
| 无名指 | 4 | 14–17 | status.ring | tip, mid, back, side |
| 小指 | 4 | 18–21 | status.pinky | tip, mid, back, side |
数据单位和范围
| 项目 | 说明 |
|---|---|
| 数据类型 | int |
| 数值范围 | 0 – 4095(12 位 ADC) |
| 物理含义 | 关节传感器经 ADC 转换后的原始码值(经 SDK 可选校准与平滑) |
数值对应(示意,实际以手套校准为准):
0:传感器低端(通常接近伸直)2048:中间量程4095:传感器高端(通常接近弯曲)
数据处理示例:
def normalize_joint(value: int) -> float:
"""将 ADC 值归一化到 [0.0, 1.0]"""
return value / 4095.0
def adc_to_angle(
value: int,
min_adc: int,
max_adc: int,
min_angle: float,
max_angle: float,
) -> float:
"""将 ADC 值线性映射到角度(需根据手套标定 min/max)"""
normalized = (value - min_adc) / (max_adc - min_adc)
return min_angle + normalized * (max_angle - min_angle)
status = controller.loop()
if status:
normalized = normalize_joint(status.thumb[0])
print(f"拇指指尖归一化: {normalized:.3f}")
angle = adc_to_angle(status.thumb[0], 500, 3500, 0.0, 90.0)
print(f"拇指指尖角度: {angle:.2f}°")4.4 高级用法示例
4.4.1 批量数据采集
import time
import csv
from psi_glove_sdk import PSIGloveController, SerialInterface
serial = SerialInterface("/dev/ttyACM0", 115200)
controller = PSIGloveController(serial, smoothing_window_size=10)
controller.connect()
data_buffer = []
for _ in range(1000):
status = controller.loop()
if status:
data_buffer.append(status.to_list()) # 每行 22 个关节
time.sleep(0.01)
with open("glove_data.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([f"joint_{i}" for i in range(22)])
writer.writerows(data_buffer)
print(f"已保存 {len(data_buffer)} 帧到 glove_data.csv")
controller.disconnect()也可使用官方 advanced_usage.py,第三个参数传入 --log 自动生成带时间戳的 CSV。
4.4.2 多手套同时使用
每只手套使用独立 SerialInterface 与 PSIGloveController:
from psi_glove_sdk import PSIGloveController, SerialInterface
import time
left_serial = SerialInterface("/dev/ttyACM0", 115200)
left_controller = PSIGloveController(left_serial)
left_controller.connect()
right_serial = SerialInterface("/dev/ttyACM1", 115200)
right_controller = PSIGloveController(right_serial)
right_controller.connect()
try:
while True:
left_status = left_controller.loop()
right_status = right_controller.loop()
if left_status and right_status:
print(
f"左手拇指尖: {left_status.thumb[0]}, "
f"右手拇指尖: {right_status.thumb[0]}"
)
time.sleep(0.01)
finally:
left_controller.disconnect()
right_controller.disconnect()4.4.3 获取指尖位姿
通过 FingertipPoseCalculator 将 22 路 ADC 映射为 URDF 关节角,再用 MuJoCo 正运动学得到五指指尖 4×4 齐次位姿(形状 (5, 4, 4),顺序:thumb → index → middle → ring → little)。
依赖:
pip install mujoco numpy ruamel.yaml
# 或:pip install -e ".[fingertip]"| 方法 | 说明 |
|---|---|
connect() / disconnect() | 连接/断开内部PSIGloveController |
get_fingertip_poses(joint_data_22) | 由 22 路 ADC 仅做 FK,返回(5, 4, 4) |
update_and_get_poses() | 读一帧 ADC 并 FK,返回(poses, urdf_angles, adc) 或全 None |
单手:实时读取
import time
from psi_glove_sdk import FingertipPoseCalculator
calc = FingertipPoseCalculator(port="/dev/ttyACM0", baudrate=115200, hand="right")
if not calc.connect():
raise RuntimeError("连接失败")
try:
while True:
poses, urdf_angles, adc = calc.update_and_get_poses()
if poses is not None:
print(f"拇指尖 xyz (m): {poses[0][:3, 3]}")
time.sleep(0.01)
finally:
calc.disconnect()双手:同步获取指尖位姿
每只手一个串口、一个 FingertipPoseCalculator(hand="left" / "right"):
import time
from psi_glove_sdk import FingertipPoseCalculator
left_calc = FingertipPoseCalculator(
port="/dev/ttyACM0", baudrate=115200, hand="left",
)
right_calc = FingertipPoseCalculator(
port="/dev/ttyACM1", baudrate=115200, hand="right",
)
if not left_calc.connect() or not right_calc.connect():
raise RuntimeError("双手连接失败")
try:
while True:
left_poses, _, _ = left_calc.update_and_get_poses()
right_poses, _, _ = right_calc.update_and_get_poses()
if left_poses is not None and right_poses is not None:
print("左拇指尖:", left_poses[0][:3, 3])
print("右拇指尖:", right_poses[0][:3, 3])
time.sleep(0.01)
except KeyboardInterrupt:
pass
finally:
left_calc.disconnect()
right_calc.disconnect()说明: 构造时会尝试从设备读校准并更新 master_slave_config URDF.yaml。可视化见 test_fingertip_visualizer.py 与 例程 3.2.4。
4.5 LRA 线性马达 play_lra
通过 Modbus 功能码 16 写寄存器 0xB0,载荷 10 字节:[m0,a0, m1,a1, …, m4,a4](拇指→小指,均为 uint8)。
from psi_glove_sdk import REG_LRA_CTRL, LRA_AMPLITUDE_MAX
modes = [5, 0, 0, 0, 0] # 拇指波形 5,其余指关闭
amps = [32, 0, 0, 0, 0] # 振幅 0–255
ok = controller.play_lra(modes, amps, slave_id=0x01)| 参数 | 范围 | 说明 |
|---|---|---|
finger_modes | 长度 5,每元素 0–10 | 0 关闭该指;1–10 波形编号 |
finger_amplitudes | 长度 5,每元素 0–255 | 播放增益;0 无驱动 |
slave_id | 1–247 | Modbus 从机地址,默认1 |
停止全部 LRA:
controller.play_lra([0, 0, 0, 0, 0], [0, 0, 0, 0, 0])TIP
mode=1 表示「波形 1」,不是「振幅 1」。低强度请减小 amplitude(如 1–64)。
4.6 配置与 URDF 路径
from psi_glove_sdk import (
load_config,
save_config,
get_default_config_path,
get_configs_dir,
get_synglove_urdf_root,
get_resources_root,
)
cfg = load_config()
urdf_root = get_synglove_urdf_root()- 开发安装:配置在
python_sdk/configs/,URDF 在仓库SynGlove_Air_URDF/。 - 离线 wheel:资源在
psi_glove_sdk/resources/内。
4.7 FingertipPoseCalculator
将手套 ADC 映射为 URDF/MuJoCo 指尖位姿,需额外安装 mujoco、numpy、ruamel.yaml:
from psi_glove_sdk import FingertipPoseCalculator
calc = FingertipPoseCalculator(
port="/dev/ttyACM0",
baudrate=115200,
hand="right",
)详见 test_fingertip_visualizer.py 与 例程 3.2.4。
4.8 Modbus 协议摘要
| 功能 | 功能码 | 地址/说明 |
|---|---|---|
| 读关节 | 0x03 | 读 22 寄存器 →StatusMessage(RequestType.READ_JOINT_POSITION) |
| LRA 播放 | 0x10 | 写0xB0,10 字节 [m0,a0,…,m4,a4] |
通信格式:Modbus RTU,帧尾 CRC16。
5. SDK打印内容说明
本章说明运行官方示例时的典型终端输出,便于对照调试。
5.1 basic_usage.py
连接成功后周期性打印五指 ADC,例如:
==================================================
PSI Glove SDK - 基础使用示例
==================================================
串口: /dev/ttyACM0
波特率: 115200
==================================================
[INFO] 正在连接到设备...
[INFO] 连接成功!
--- 帧 #0 ---
拇指: 2048, 1856, 2304, 1792, 2176, 1920
食指: 1920, 2240, 1664, 2112
...- 拇指 6 个整数,其余四指各 4 个整数。
- 数值范围约 0–4095(12 位 ADC,经 SDK 平滑与可选校准)。
5.2 advanced_usage.py
每 50 帧打印拇指各关节的角度、归一化值与原始 ADC;结束时输出拇指指尖统计信息。使用 --log 时生成 psi_glove_data_*.csv。
5.3 lra_play_example.py
正常流程:
[INFO] 连接成功
[INFO] play_lra(thumb wave=1 amp=32) -> Trueplay_lra 返回 False 时检查:串口占用、固件是否支持 LRA、参数长度是否为 5。
5.4 test_fingertip_visualizer.py
启动 MuJoCo 窗口后,终端可能打印指尖坐标或关节映射日志;无手套连接时会报串口错误。

需保证 URDF 路径正确:开发安装使用仓库 SynGlove_Air_URDF/;离线 wheel 使用包内 resources。
5.5 日志级别
示例均使用 logging:
import logging
logging.basicConfig(level=logging.INFO)调试通信可将级别设为 DEBUG(若 SDK 模块已配置相应 handler)。
6. 连接状态查询与故障排查
6.1 连接状态
if controller.is_connected():
status = controller.loop()
else:
print("未连接,请调用 connect()")断开时调用 controller.disconnect(),并释放串口供其他程序使用。
6.2 串口与权限
| 现象 | 处理 |
|---|---|
LinuxPermission denied | sudo usermod -aG dialout $USER 后重新登录 |
| 找不到设备 | ls /dev/ttyACM* / Windows 设备管理器查看 COM 口 |
Device or resource busy | 关闭 AirHandViewer、旧示例或其它占用串口的进程 |
6.3 Modbus 读数失败
- 确认波特率与固件一致(常用
115200或500000)。 - 适当增大
SerialInterface.timeout(如0.01)。 loop()返回None时可用get_last_status()取上一帧有效数据。
6.4 LRA 相关问题
| 现象 | 可能原因 | 建议 |
|---|---|---|
play_lra 返回 True 但无振动 | 固件 LRA 任务未就绪或消息队列未满 | 刷写含lra_message_buffer_preinit 的 V2 固件 |
| 连接后第一次 LRA 无效 | 早期固件 MessageBuffer 创建过晚 | 同上,升级固件 |
| 停止后仍有微弱振动 | mode=0 未清零增益 | 升级固件(PLAY_GAIN 归零修复) |
Write timeout | MCU 忙于 I2C | 降低下发频率;使用 SDK 默认写超时 |
| 强度“很大” | 误将mode 当振幅 | mode 选波形,amplitude 用 1–64 试探 |
停止所有指马达:
ctrl.play_lra([0, 0, 0, 0, 0], [0, 0, 0, 0, 0])6.5 离线 Wheel 安装失败
- 错误
is not a supported wheel on this platform:在目标架构上重新执行package_offline_wheel.py,或指定正确的--plat-name。 - 缺少 URDF / 配置:确认安装的是离线构建产物,而非纯
pip install -e .的开发树。
6.6 导入错误
ImportError: cannot import name 'play_lra'说明加载了旧版已安装的 psi_glove_sdk。处理:
pip uninstall psi-glove psi-air-glove psi_glove_sdk # 视已安装包名而定
cd psi-air-glove-SDK/psi-air-glove-SDK/python_sdk && pip install -e .