诊断与错误
设备状态、自动连接恢复与错误处理。
诊断与错误
先读: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:
| 阶段 | connected | stale | last_error | reconnect_count |
|---|---|---|---|---|
| 接收中,数据正常流动 | true | false | 已清除 | 不变 |
| 恢复中 | false | true | 记录断开原因 | 不变 |
| 连接已恢复,尚未接收 | true | true | 已清除 | 递增一次 |
| 接收已恢复 | true | false | 已清除 | 保持恢复后的计数 |
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 | 当前汇总中的告警和错误数量 |
devices | source ID 到各设备健康状态的映射 |
last_error | 最近一次 SDK 错误 |
runtime_overrun | SDK 调度是否发生过超时 |
topic_callback_error | callback 是否发生过未处理异常 |
单设备状态的常用字段:
| 常用字段 | 含义 |
|---|---|
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 | 参数或配置值无效 |
ClosedHandleError | SDK 或 Glove 已关闭 |
StaleUpdateError | update 等待 token 已使用或失效 |
LifecycleError | 生命周期顺序或运行模式不合法 |
UnavailableFeatureError | 当前平台、安装包或功能不可用 |
CommandRejectedError | SDK 拒绝命令 |
GloveControlError | 设备控制命令失败:未连接、设备忙、超时等,原因见 kind(GloveControlErrorKind) |
NotFoundSelectionError | 没有匹配的设备或 target |
AmbiguousSelectionError | 选择条件匹配多个设备或 target |
InternalError | SDK 无法完成当前操作 |
PanicError | SDK 执行异常已转换为 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()