SDKPython SDK

诊断与错误

设备状态、自动连接恢复与错误处理。

当前版本 · 1.4.0

诊断与错误

先读:Debug 日志(先开日志再复现问题) · 读完你能:读懂设备状态、自动连接恢复与错误类型

按症状定位问题见 常见问题;这一章给出读取设备状态与处理错误的工具。

设备状态与诊断

设备状态可以持续订阅,也可以非阻塞读取最新值:

from qnbot_sdk import Sdk
from qnbot_sdk.glove import GloveConfig

sdk = Sdk(devices=(GloveConfig(),))
glove = sdk.glove()
try:
    status = glove.device().status()
    status.subscribe(
        lambda sample: print(sample.value.connected, sample.value.last_error)
    )
    glove.start()
    glove.run_forever()
finally:
    glove.close()

常用字段:

常用字段含义
connected当前是否已连接
stale当前数据是否已经过期或尚未开始流动
last_error最近一次设备错误
reconnect_count成功恢复连接的累计次数

完整字段、类型和可空行为见 GloveStatus。

自动连接恢复

自动恢复只用于已经成功启动、随后意外断开的手套;首次连接失败会由 start() 直接返回。恢复只影响断开的那只手套,其他手套继续运行。

流程图渲染中

恢复期间各阶段的状态字段;失败的重试不会增加 reconnect_count:

阶段connectedstalelast_errorreconnect_count
接收中,数据正常流动truefalse已清除不变
恢复中falsetrue记录断开原因不变
连接已恢复,尚未接收truetrue已清除递增一次
接收已恢复truefalse已清除保持恢复后的计数

reconnect_count 在连接成功恢复时递增;stale 在接收恢复后才变为 false。已确认身份的设备会核对原设备;配置为未验证的固定端口按对应的受限路径恢复。

断连、取消与重连期间的行为:

  • 断连期间调用 haptics().set() 设置震动或发送其他设备命令会立即以 not-connected 错误失败,不排队,也不重放;当前震动设置被清空,恢复后需要重新设置。
  • 显式调用 stop() 或 close() 会取消恢复。
  • 对同一已确认设备,已经就绪且仍有效的 SDK 处理后的数据在恢复后继续可用,不会仅因重连而重新标定。

健康状态

健康状态可以在运行期间由其他逻辑读取,也可以在 run_forever() 返回后、close() 前读取:

health = glove.health()

print(health.ok)
print(health.warning_count)
print(health.error_count)
print(health.last_error)
print(health.runtime_overrun)
print(health.topic_callback_error)

for source_id, device_health in health.devices.items():
    print(source_id, device_health.connected, device_health.stale)

health.devices 的键是 SDK 返回的 source_id。需要定位具体手套时,可将该键与已选择设备的 device.source_id 对照;设备选择仍使用 name 或 side,不要解析 source_id 的字符串格式。

sdk.health() 返回整个 SDK 的健康状态;glove.health() 返回全部已配置手套的健康状态。只需查看一只手套时,先用 glove.device(side=Side.LEFT) 或配置名称选中它,再调用 device.health();device.source_id 可与汇总结果的 health.devices 键对照。

汇总状态的常用字段:

常用字段含义
ok当前汇总状态是否健康
warning_count / error_count当前汇总中的告警和错误数量
devicessource ID 到各设备健康状态的映射
last_error最近一次 SDK 错误
runtime_overrunSDK 调度是否发生过超时
topic_callback_errorcallback 是否发生过未处理异常

单设备状态的常用字段:

常用字段含义
connected设备是否已连接
stale设备数据是否过期或尚未开始流动
last_error最近一次设备错误

完整字段、类型和可空行为见 Health 和 DeviceHealth。

建议用法: 判断运行期间是否健康,应在停止请求前读取并记录 running health。以下后台模式启动后先等待自身的首帧或就绪条件;主动停止完成后,再在关闭前读取 stopped lifecycle health,用于确认停止后的 connected/stale 状态:

glove.run_background()

# 先等待自身的首帧或就绪条件。
running_health = glove.health()
print("running health", running_health)

glove.request_stop()
glove.join()

stopped_health = glove.health()
print("stopped lifecycle health", stopped_health)

停止遥测后设备会进入 stale=true,所以即使 warning_count=0、error_count=0,ok 也可能是 ok=false。这是停止后的预期状态,不表示运行失败,也不会改变 Health.ok 的含义。前台 run_forever() 会阻塞当前线程,需要在运行期间检查状态时,应通过已经注册的 callback 或 session 处理。完整的前台和后台顺序分别见 foreground_runtime.py 与 background_runtime.py。

错误处理

按失败场景捕获最具体的异常类型,并优先读取异常提供的结构化字段:

错误典型含义
InvalidArgumentError参数或配置值无效
ClosedHandleErrorSDK 或 Glove 已关闭
StaleUpdateErrorupdate 等待 token 已使用或失效
LifecycleError生命周期顺序或运行模式不合法
UnavailableFeatureError当前平台、安装包或功能不可用
CommandRejectedErrorSDK 拒绝命令
GloveControlError设备控制命令失败:未连接、设备忙、超时等,原因见 kind(GloveControlErrorKind)
NotFoundSelectionError没有匹配的设备或 target
AmbiguousSelectionError选择条件匹配多个设备或 target
InternalErrorSDK 无法完成当前操作
PanicErrorSDK 执行异常已转换为 Python 错误

选择错误还提供结构化字段:

from qnbot_sdk import AmbiguousSelectionError

try:
    glove = sdk.glove()
    device = glove.device()
except AmbiguousSelectionError as error:
    print(error.selector_kind)
    print(error.selector_value)
    print(error.candidates)

不要通过解析错误消息判断错误类型或选择结果。参数/配置问题通常先处理 InvalidArgumentError,设备或 target 选择处理 NotFoundSelectionError 和 AmbiguousSelectionError,运行顺序与后台错误处理 LifecycleError;只需要统一记录未分类 SDK 失败时,再在外层捕获 QnBotError。

接入流程: 在外层捕获 SDK 错误,资源释放仍放在 finally 中:

from qnbot_sdk import QnBotError

try:
    glove.start()
    glove.run_forever()
except QnBotError as error:
    print(error.message)
finally:
    glove.close()