SDKPython SDK

迁移

从 SDK 1.3.0 升级到 1.4.0,以及更早版本升级时的 API 替换与流程调整。

当前版本 · 1.4.0

迁移

从 1.3.0 升级到 1.4.0

1.4.0 的主要迁移动作是统一时间单位。现有单手套应用不需要改成组合设备,也不要求调用 sync_time();只有使用外部时间源、读取时间字段或准备接入 Exo + Glove 时,才需要完成对应步骤。

同时更新 Core 与 Glove

安装 qnbot-sdk-glove 1.4.0,让 pip 解析匹配的 Core 依赖;不要让已打包程序继续携带 1.3.0 的 native 库:

python -m pip install --upgrade "qnbot-sdk-glove==1.4.0"

如果应用会打包 wheel、native 库或虚拟环境,应清理旧产物后重新构建并部署。

将公开数值时间改为毫秒

1.4.0 的 Glove 帧、运行状态、采集、标定和派生数据统一使用毫秒。新输出只提供 timestamp_ms;所有把时间当秒读取、存储、相减或传给下游协议的代码都需要同步修改。

外部帧的新写法:

frame = ExternalGloveFrame(
    thumb=thumb,
    index=index,
    middle=middle,
    ring=ring,
    pinky=pinky,
    timestamp_ms=1_700_000_000_123.0,
)

旧的 timestamp_sec 仍可作为兼容输入,SDK 会明确执行 timestamp_ms = timestamp_sec * 1000。不要根据数值大小猜测单位,也不要同时传入两个字段; timestamp_ms 与 timestamp_sec 同时存在时会抛出参数错误。

按需设置外部时间基准

如果应用需要让所有 Glove source 使用同一个外部绝对时间基准,在 Glove 域调用公开入口 Glove.sync_time()。参数是绝对 Unix 毫秒,不是秒或纳秒:

import time

sdk = Sdk(devices=(GloveConfig(),))
glove = sdk.glove()
glove.sync_time(time.time() * 1_000.0)
glove.start()

可以在运行中再次调用 sync_time();后续未显式携带时间的 Glove 帧会从新基准继续推进,已有订阅和生命周期不会重置。显式提供的 timestamp_ms 优先,不会被共享时钟覆盖。不调用时,SDK 使用主机 Unix 毫秒时间。该操作只调整 Glove 域,不会修改 Exo 时间。

按需接入 Exo + Glove 组合设备

组合设备是 1.4.0 的新增能力,不影响原有 GloveConfig。需要共享串口时,改用 CompositeExoGloveConfig,并从同一个 Sdk 取得 sdk.glove() 与 sdk.exo();完整配置和能力边界见手套 + 外骨骼融合方案。

迁移检查清单

  • 安装匹配的 Core 与 Glove 1.4.0,清理打包产物中的 1.3.0 native 库
  • 将输出字段和下游协议中的秒值改为毫秒,优先使用 timestamp_ms
  • 如暂时保留 timestamp_sec 输入,确认代码没有同时传入 timestamp_ms
  • 对外部时间源使用绝对 Unix 毫秒,并在需要时调用 glove.sync_time()
  • 只有使用融合硬件时才改用 CompositeExoGloveConfig
  • 用真实设备复测采集记录、时间对齐、断线恢复和关闭流程

从 1.2.x 升级到 1.3.0

本文只列出 Glove SDK 从 1.2.0 升级到 1.3.0 时必须修改的内容。SerialConnection、后台运行方式和算法包 package_id 语义没有变化,因此不列入本次不兼容变更。

采集接口从 Glove 移到 GloveDevice

1.2.0 中,应用通过 Glove 调用采集接口,同时传入设备选择参数:

capture = glove.start_capture(
    package_ids=["qnbot-dexhand"],
    operator_id="operator-001",
    source=None,
    side=Side.LEFT,
    force=False,
)

其中 source 用于按设备名称选择设备,side 用于按左右手选择设备;source 为空时根据 side 选择设备。

1.3.0 中,需要先获取目标设备,再执行采集:

device = glove.device(side=Side.LEFT)

capture = device.start_capture(
    package_ids=["qnbot-dexhand"],
    operator_id="operator-001",
    force=False,
)

也可以按名称选择:

device = glove.device("my-glove")

设备选择从采集请求中独立出来,由应用先明确选择 GloveDevice。

capture_status() 移到 GloveDevice

1.2.0:

readiness = glove.capture_status(
    package_ids=["qnbot-dexhand"],
    operator_id="operator-001",
    source=None,
    side=Side.LEFT,
)

1.3.0:

device = glove.device(side=Side.LEFT)

readiness = device.capture_status(
    package_ids=["qnbot-dexhand"],
    operator_id="operator-001",
)

start_calibration() 移到 GloveDevice

1.2.0:

calibration = glove.start_calibration(
    completed_capture_session=capture,
    targets=targets,
)

1.3.0:

calibration = device.start_calibration(
    completed_capture_session=capture,
    targets=targets,
)

采集会话和标定会话由同一个 GloveDevice 管理:

device = glove.device(side=Side.LEFT)

capture = device.start_capture(
    package_ids=["qnbot-dexhand"],
    operator_id="operator-001",
)

calibration = device.start_calibration(
    completed_capture_session=capture,
    targets=targets,
)

CalibrationInteractionMode 更名

1.2.0 的 CalibrationInteractionMode 在 1.3.0 更名为 CaptureInteractionMode,取值不变(AUTO_TERMINAL、EXTERNAL):

from qnbot_sdk import CaptureInteractionMode

项目代码、配置文件映射和自定义封装中使用旧枚举名称的地方都需要修改。

采集交互配置从 CalibrationConfig 移到 CaptureConfig

1.3.0 把采集阶段配置和标定阶段配置分开:interaction 和 operator_id 属于采集阶段,已从 CalibrationConfig 移到 CaptureConfig;CalibrationConfig 只保留 force。

如果 1.2.0 项目把这两个字段写在 CalibrationConfig 中:

algorithms = AlgorithmsConfig(
    calibration=CalibrationConfig(
        interaction=CalibrationInteractionMode.EXTERNAL,
        operator_id="operator-001",
        force=False,
    ),
)

1.3.0 应改为:

algorithms = AlgorithmsConfig(
    capture=CaptureConfig(
        interaction=CaptureInteractionMode.EXTERNAL,
        operator_id="operator-001",
    ),
    calibration=CalibrationConfig(force=False),
)

两个 force 的含义和归属没有变化,字段定义见 CaptureConfig 与 CalibrationConfig。

迁移检查清单

  • 将 glove.start_capture() 改为 device.start_capture()
  • 将 glove.capture_status() 改为 device.capture_status()
  • 将 glove.start_calibration() 改为 device.start_calibration()
  • 将 CalibrationInteractionMode 改为 CaptureInteractionMode
  • 将 interaction 和 operator_id 从 CalibrationConfig 移到 CaptureConfig
  • 确保采集和标定使用同一个 GloveDevice

从 1.1.x 升级到 1.2.0

以下仅列出升级时需要修改现有代码或重新构建的不兼容变化。完整的新增功能、修复和版本变化请查看 Python SDK 更新日志。

不兼容项原有用法当前行为迁移动作
Core 与 Glove 安装包可以分别替换 wheel,或让已打包程序继续携带旧版 native 库Core 与 Glove 属于同一套公开 API 和 native ABI,混用不同发布版本不受支持删除旧版 wheel,同时安装同一发布版本的 Core 和 Glove;不要混用。若程序将 SDK 打包进可执行文件、镜像或其他交付产物,应清理旧构建内容并重新构建
connect() / start() / stop() 生命周期connect() 建立设备连接,start() 再启动数据流;停止后可另外调用 disconnect()connect() 已弃用并保留为成功的空操作;start() 负责连接并启动,stop() 同时停止并断开;disconnect() 委托给 stop()不再依赖 connect() 判断连接成功;准备好数据读取和订阅后直接调用 start(),结束时调用 stop(),最后调用 close()
SDK 创建阶段可以先创建未完成设备解析的 SDK,再到 connect() 时发现设备、读取身份和补全配置创建 Sdk 时会完成设备发现与身份探测,并解析 source、target 和算法包;无设备、端口占用、身份不匹配或算法包缺失可能在构造函数中抛错在创建 SDK 前准备好设备和算法包,把构造和 start() 都放入异常处理;设备、配置或已安装算法包变化后重新创建 SDK
get_device_info()每次调用都会向已连接设备发起新的 id 身份事务返回 SDK 创建阶段保存的已验证身份快照,可在 start() 前调用;显式端口回退但身份未验证时抛出 UnavailableFeatureError不要依赖该调用刷新设备身份;需要展示身份时读取快照,并在允许未验证设备的部署中处理 UnavailableFeatureError
Capture 请求参数capture_status() 和 start_capture() 使用 candidate_ids参数改为非空 package_ids,每项必须是非空算法包 ID将所有 candidate_ids= 改为 package_ids=,并确保序列非空
Capture 结果与 Session 所有权CaptureSession.result() 返回 CaptureSet;后续标定接收该 CaptureSetresult() 返回只读摘要 CaptureResult;后续标定直接接收仍打开且已完成的 CaptureSession删除 CaptureSet / CaptureSetSnapshot 逻辑;在标定完成前保持原 CaptureSession 打开,并把它传给 start_calibration()
Calibration 会话 APIstart_calibration(capture_set=..., package_id=..., target=...) 为一个 target 返回一个 CalibrationJobstart_calibration(completed_capture_session=..., targets=(...)) 返回一个 CalibrationSession,按顺序处理非空且不重复的 target 序列;result() 返回结果 tuple,wait() 可阻塞等待完成删除独立 CalibrationJob 流程和 package_id 参数,改为一次创建 CalibrationSession,通过 snapshot()、result()、wait()、cancel() 和 close() 管理
Capture 控制与进度device.calibration_control(name) 按 target 提交确认;calibration_progress(name) 同时包含动作提示、样本数和保存状态source 级动作改由 device.capture_progress() 与 device.capture_control() 处理;target 级 device.calibration_progress(name) 只报告 Calibration 计算状态将 calibration_control() 改为 capture_control();从 CaptureProgress.stage 读取动作和样本进度,从 CalibrationProgress.job 读取各 target 状态;confirm()、skip()、cancel() 使用 request_id,retry() 使用 stage_id
Capture 状态与字段CaptureSessionState 包含 CREATED、AWAITING_CONFIRMATION、COLLECTING;CaptureStageState 包含 REUSED、CAPTURED、FAILED;快照使用 stage_runs 和字符串 failure,CapturePlan 含 resolved_packagesSession 的进行中状态统一为 RUNNING;动作状态进入 CaptureStageProgress,完成使用 COMPLETED,复用由 origin=REUSED 表示;快照使用 stage_progress 和结构化 CaptureFailure,resolved_packages 已删除更新状态分支和界面字段:CAPTURED 改为 COMPLETED,从 origin 判断复用,从 Session 的结构化 failure 判断失败,并将 stage_runs 改为 stage_progress;不要再读取 resolved_packages
Calibration 状态与结果字段CalibrationJobState 使用 RUNNING、SAVING、COMPLETED、FAILED;CalibrationJobSnapshot 和 CalibrationResult 含 package_id、package_versionCalibrationSessionState 与 CalibrationJobState 支持取消,job 还包含 PENDING;保存过程归入 RUNNING;进度使用 CalibrationJobProgress / CalibrationSessionSnapshot,CalibrationResult 仅保留 record_id、source_id、target_id、created_at删除 SAVING 和 CalibrationJobSnapshot 分支,改用 Session/job 两级状态;如需算法包 ID 或版本,从自身 target 配置维护,不再从 CalibrationResult 读取
标定存储配置通过 CalibrationStoreConfig 或 CalibrationConfig.store 指定目录这两个公开入口已删除,标定记录统一保存在 <QNBOT_HOME>/glove/calibrations删除旧存储配置;如需更改数据根目录,在创建 Sdk 前设置 QNBOT_HOME,并确保 CLI 与 SDK 使用相同值
Debug 日志目录通过 DebugConfig.log_dir 指定目录DebugConfig.log_dir 已删除;QNBOT_HOME 决定日志根目录,日志位于 <QNBOT_HOME>/logs,每次诊断运行使用独立 session 目录删除 DebugConfig.log_dir;如需更改日志根目录,在创建 Sdk 前设置 QNBOT_HOME
Debug detail 与 module使用 DebugDetail.RAW 和任意 module 字符串,例如 serial、glove、bufferRAW 已删除;详细记录使用 FULL。可选模块改为 DebugModule.TRANSPORT、DEVICE、CAPTURE、CALIBRATION、RETARGETING、OUTPUT将 DebugDetail.RAW 改为 FULL 或 SUMMARY;把旧 module 名替换为对应 DebugModule 枚举值
Skeleton 关节角与标定skeleton().joint_angles() 使用 24 个 active joints,索引 1 是原有第二个关节;已有标定对应旧 Skeleton 版本关节角增加为 25 个,索引 1 新增 <side>_thumb_cmc_flexion,原索引 1–23 后移一位;Skeleton pose 仍为 25 个节点,旧版本标定不会作为当前兼容记录复用将固定长度、索引映射和下游协议更新为 25 个关节,优先按关节名读取;升级后允许 Skeleton 重新标定