Skip to content

PSI 手套 Python SDK 使用手册

ψ-SynGlove Air Python SDK 完整文档。

📋 目录

  1. 硬件安装方法说明
  2. SDK安装和配置方法
  3. 例程编译和调用方法
  4. SDK接口调用说明
  5. SDK打印内容说明
  6. 连接状态查询与故障排查

1. 硬件安装方法说明

本文适用于 ψ-SynGlove Air(Air Hand V2):22 路关节 ADC 采集,五指可选配 LRA 线性马达 触觉反馈。通信协议与 SDK Modbus 章节一致(读关节、写 0xB0 LRA)。

SDK 源码仓库路径:psi-air-glove-SDK/psi-air-glove-SDK/(含 python_sdkcpp_sdkros2_sdk)。

1.1 硬件清单

  • PSI 数据手套(左手/右手)
  • USB 数据线

1.2 硬件连接步骤

┌────────────────┐                        ┌─────────────┐
│  PSI 数据手套  │ ──────── USB ───────→ │   计算机    │
│  (左手/右手)   │   (虚拟串口通信)       │  (运行SDK)  │
└────────────────┘                        └─────────────┘

连接步骤:

  1. 连接手套:使用 USB 数据线将数据手套直接连接到计算机 USB 接口
  2. 手套供电:手套通过 USB 接口供电
  3. 虚拟串口:计算机会自动创建虚拟串口设备用于通信
  4. 确认设备
    • Linux: 运行 ls /dev/ttyUSB* /dev/ttyACM* 查看设备(通常为 /dev/ttyACM0
    • Windows: 打开设备管理器查看 COM 口(如 COM31)
    • macOS: 运行 ls /dev/tty.usbmodem*ls /dev/cu.usbmodem*

注意事项:

  • 手套使用 USB 供电,无需额外电源适配器
  • 首次连接时,操作系统会自动安装 USB CDC 驱动

1.3 串口权限设置(Linux)

bash
# 将当前用户添加到 dialout 组
sudo usermod -a -G dialout $USER

# 注销后重新登录,或使用以下命令立即生效
newgrp dialout

# 验证权限
ls -l /dev/ttyACM0

2. 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 系统要求

项目要求
Python3.7+(离线 wheel 推荐 3.10)
操作系统Linux / Windows / macOS
基础依赖pyserial >= 3.5
可选依赖numpy(平滑加速)、mujoco / ruamel.yaml(指尖 FK 与可视化)

2.2 从源码安装

bash
# 进入 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 的场景。

bash
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.10cp311 对应 3.11,以此类推
操作系统当前 wheel 为 Linux x86_64 / aarch64 manylinux 标签,不支持 Windows / macOS 直接安装
架构linux_x86_64aarch64 不可混用,须与目标机 uname -m 一致

2. 安装

bash
# 进入 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.whl

3. 验证安装

bash
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()Noneurdf_root 下存在 SynGlove_Air_URDF/,说明配置与 URDF 已随 wheel 安装完整。

4. 指尖位姿 / MuJoCo 可视化(可选)

离线 wheel 仅包含 pyserial 与包内 resources;运行 test_fingertip_visualizer.pyFingertipPoseCalculator 还需额外安装:

bash
pip install mujoco numpy ruamel.yaml

安装完成后即可运行 examples/ 下示例(见 §3 例程)。

2.4 可配置参数

SerialInterface

参数类型默认说明
portstr必填串口路径,如/dev/ttyACM0COM3
baudrateint115200波特率,常用115200500000921600
timeoutfloat0.01读超时(秒)
auto_connectboolFalse构造时是否自动连接
mockboolFalse模拟模式(无硬件测试)

LRA 连续下发时,写超时默认放宽为 max(1s, 读超时×10),减轻 Write timeout

PSIGloveController

参数类型默认说明
communication_interfaceCommunicationInterface必填SerialInterface 实例
smoothing_window_sizeint10移动平均窗口;越大越平滑、延迟越高
adc_calibrationADCCalibrationParams内置默认可选 ADC 三次多项式校准

2.5 典型配置示例

python
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.pyMuJoCo 实时显示指尖位姿与坐标系

3.2 例程运行方法

运行前建议已在 python_sdk 目录执行 pip install -e .

3.2.1 基础用法示例

bash
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 高级用法示例

bash
# 运行高级示例
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 触觉示例

bash
python3 lra_play_example.py COM3 115200
python3 lra_play_example.py /dev/ttyACM0 921600

可选参数:--slave(Modbus 从机地址)、--step-sec(每档保持时间)、--amp-max(振幅上限,默认 64)。

示例逻辑:拇指出厂波形,振幅从 1 递增到 amp_maxmode=0 关闭该指马达。

3.2.4 指尖可视化示例

依赖:mujoconumpyruamel.yaml,以及 URDF(开发态在 SynGlove_Air_URDF/,离线 wheel 在 psi_glove_sdk/resources/)。

bash
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 索引属性访问
拇指60–5status.thumb
食指46–9status.index
中指410–13status.middle
无名指414–17status.ring
小指418–21status.pinky

拇指 6 路顺序:tip, mid, back, back2, side, rotate。其余四指:tip, mid, back, side


4. SDK接口调用说明

4.1 核心类和方法

4.1.1 SerialInterface 类

串口通信接口类,处理底层 Modbus RTU 硬件通信。

python
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)
)
参数类型默认说明
portstr必填串口设备路径
baudrateint115200通信波特率
timeoutfloat0.01读超时(秒)
auto_connectboolFalse构造时是否自动connect()
mockboolFalse模拟模式
write_timeoutfloat| NoneNone写超时;LRA 连续下发时建议保持默认

4.1.2 PSIGloveController 类

主控制器类,管理连接、Modbus 读关节、移动平均平滑、LRA 触觉下发。

python
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)boolLRA 线性马达控制(Modbus 写0xB0

4.2 读取主手数据的完整流程

python
#!/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。StatusMessagejoints 为主字段,并通过属性访问各指数据:

python
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 索引访问方式顺序说明
拇指60–5status.thumbtip, mid, back, back2, side, rotate
食指46–9status.indextip, mid, back, side
中指410–13status.middletip, mid, back, side
无名指414–17status.ringtip, mid, back, side
小指418–21status.pinkytip, mid, back, side

数据单位和范围

项目说明
数据类型int
数值范围0 – 4095(12 位 ADC)
物理含义关节传感器经 ADC 转换后的原始码值(经 SDK 可选校准与平滑)

数值对应(示意,实际以手套校准为准):

  • 0:传感器低端(通常接近伸直)
  • 2048:中间量程
  • 4095:传感器高端(通常接近弯曲)

数据处理示例:

python
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 批量数据采集

python
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 多手套同时使用

每只手套使用独立 SerialInterfacePSIGloveController

python
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 获取指尖位姿

通过 FingertipPoseCalculator22 路 ADC 映射为 URDF 关节角,再用 MuJoCo 正运动学得到五指指尖 4×4 齐次位姿(形状 (5, 4, 4),顺序:thumb → index → middle → ring → little)。

依赖:

bash
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

单手:实时读取

python
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()

双手:同步获取指尖位姿

每只手一个串口、一个 FingertipPoseCalculatorhand="left" / "right"):

python
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)。

python
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–100 关闭该指;1–10 波形编号
finger_amplitudes长度 5,每元素 0–255播放增益;0 无驱动
slave_id1–247Modbus 从机地址,默认1

停止全部 LRA:

python
controller.play_lra([0, 0, 0, 0, 0], [0, 0, 0, 0, 0])

TIP

mode=1 表示「波形 1」,不是「振幅 1」。低强度请减小 amplitude(如 1–64)。

4.6 配置与 URDF 路径

python
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 指尖位姿,需额外安装 mujoconumpyruamel.yaml

python
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 寄存器 →StatusMessageRequestType.READ_JOINT_POSITION
LRA 播放0x100xB0,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) -> True

play_lra 返回 False 时检查:串口占用、固件是否支持 LRA、参数长度是否为 5。

5.4 test_fingertip_visualizer.py

启动 MuJoCo 窗口后,终端可能打印指尖坐标或关节映射日志;无手套连接时会报串口错误。

指尖可视化示例运行效果

需保证 URDF 路径正确:开发安装使用仓库 SynGlove_Air_URDF/;离线 wheel 使用包内 resources。

5.5 日志级别

示例均使用 logging

python
import logging
logging.basicConfig(level=logging.INFO)

调试通信可将级别设为 DEBUG(若 SDK 模块已配置相应 handler)。


6. 连接状态查询与故障排查

6.1 连接状态

python
if controller.is_connected():
    status = controller.loop()
else:
    print("未连接,请调用 connect()")

断开时调用 controller.disconnect(),并释放串口供其他程序使用。

6.2 串口与权限

现象处理
LinuxPermission deniedsudo usermod -aG dialout $USER 后重新登录
找不到设备ls /dev/ttyACM* / Windows 设备管理器查看 COM 口
Device or resource busy关闭 AirHandViewer、旧示例或其它占用串口的进程

6.3 Modbus 读数失败

  • 确认波特率与固件一致(常用 115200500000)。
  • 适当增大 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 timeoutMCU 忙于 I2C降低下发频率;使用 SDK 默认写超时
强度“很大”误将mode 当振幅mode 选波形,amplitude 用 1–64 试探

停止所有指马达:

python
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。处理:

bash
pip uninstall psi-glove psi-air-glove psi_glove_sdk  # 视已安装包名而定
cd psi-air-glove-SDK/psi-air-glove-SDK/python_sdk && pip install -e .