SDKC++ SDK

设备发现与连接

发现与固定手套、单只或多只选择与 Receiver。

当前版本 · 1.4.0

设备发现与连接

默认配置可以自动发现唯一支持的串口手套;需要固定端口、序列号或多只手套时,按下面对应的小节配置 GloveConfig。

发现设备

需要在创建 Sdk 前列出设备时,可调用 qnbot::discover_gloves()。返回的 std::vector<qnbot::DiscoveredGlove> 包含串口、左右手、设备 SN 和可选逐设备错误:

const auto devices = qnbot::discover_gloves();
const auto selected = std::find_if(
    devices.begin(), devices.end(),
    [](const auto& device) { return !device.error; });

if (selected != devices.end() && selected->hand) {
    qnbot::SerialConnection connection;
    connection.port = selected->port;
    qnbot::GloveConfig config{*selected->hand, connection};
}

端口被其他进程占用时,该设备仍保留在结果中,port 可用,并通过 qnbot::GloveDiscoveryErrorCode::port_busy(稳定错误码 PORT_BUSY)标识。程序逻辑应判断枚举,不要解析诊断 message。发现结果是调用时刻的快照;设备插拔后应重新发现。完整示例见 discover_gloves.cpp。

单只手套

单手套场景会自动发现唯一连接的受支持手套:

qnbot::SdkConfig config;
config.devices = {qnbot::GloveConfig{}};
qnbot::Sdk sdk(std::move(config));

未配置 side 的单手套声明仍要求只有一个未占用候选。只有自动发现不成立时才需要固定选择,见 连接设备。

两只手套

同时连接一只左手套和一只右手套时,只需要声明 side,无需显式设置 connection:

qnbot::GloveConfig left;
left.side = qnbot::Side::left;

qnbot::GloveConfig right;
right.side = qnbot::Side::right;

qnbot::SdkConfig config;
config.devices = {left, right};

SDK 按 side 唯一分配设备,串口枚举顺序不会决定左右数据流。每只直连手套最多分配一次;受支持的 Receiver 可以承载左右两个 source。直连候选缺少某一侧、同一侧存在多个候选,或 SDK 创建期间设备信息与发现结果不一致时,SDK 创建失败。Receiver 中手套在 SDK 创建期间离线的行为见下文。两只同侧手套必须分别显式配置 port 或 serial_number。

未提供设备定位信息时,SerialConnection{} 使用上述自动发现和 side 分配。

多只手套

连接三只及以上手套时,至少有两只位于同一侧。如需分别选择每只手套,应为每项配置设置唯一的 name,并使用不同的 port 或 serial_number 固定同侧手套。name 只用于应用选择手套,不替代设备定位信息;如果其他条件已经唯一,SDK 不会仅因省略 name 而拒绝创建。

qnbot::SerialConnection left_primary_connection;
left_primary_connection.port = "/dev/ttyUSB0";
qnbot::GloveConfig left_primary{qnbot::Side::left, left_primary_connection};
left_primary.name = "left-primary";

qnbot::SerialConnection left_backup_connection;
left_backup_connection.port = "/dev/ttyUSB1";
qnbot::GloveConfig left_backup{qnbot::Side::left, left_backup_connection};
left_backup.name = "left-backup";

qnbot::GloveConfig right;
right.side = qnbot::Side::right;
right.name = "right";

qnbot::SdkConfig config;
config.devices = {left_primary, left_backup, right};
qnbot::Sdk sdk(std::move(config));
auto selected = sdk.glove().device("left-primary");

没有实体手套,或要接入自研设备? 这两种情况都可以用外部输入逐帧提供手部帧,读取路径与实体手套相同。配置方式与帧约束见 外部输入。

连接设备

Sdk 构造返回前完成设备发现与身份校验,start() 才建立持续运行的连接与数据流,见 生命周期。需要指定具体设备时,用下面的连接方式。

指定端口或序列号

固定部署可以指定串口:

qnbot::SerialConnection connection;
connection.port = "/dev/ttyUSB0";

qnbot::GloveConfig device_config{qnbot::Side::right, connection};
device_config.name = "primary";

当 SDK 能将该端口识别为受支持的有线直连手套,且同时显式提供 port 和 side 时, SDK 仍会优先验证设备身份。对于无法报告设备身份的旧版有线直连手套,SDK 会使用配置的串口和左右手继续连接,并发出“身份未验证”告警。断线恢复只重试该 port,无法确认恢复后是否仍是同一只实体手套。自动发现、只提供 port、只提供 side、按 serial_number 选择、无线 Receiver 以及无法识别端口类型时仍要求设备身份校验,不能使用这一兼容行为。

也可以通过 USB 序列号选择。空的 SerialConnection{} 使用自动发现:

qnbot::SerialConnection by_serial;
by_serial.serial_number = "YOUR-SERIAL-NUMBER";

显式设置设备定位信息时,auto_discover=true、port 和 serial_number 互斥;baudrate 可选。

无线 Receiver(实验性功能)

Receiver 当前是实验性功能,稳定性、支持范围和公开行为后续可能变化,不建议把当前行为作为长期兼容承诺。

受支持的无线 Receiver 与直连有线手套使用同一个 qnbot::GloveConfig 和串口选择方式,不需要 Receiver 专用配置类型。一条声明仍只表示一只手套 source;自动连接左右手时,分别声明 qnbot::Side::left 和 qnbot::Side::right,SDK 可以通过同一个 Receiver 解析两侧手套。

固定部署时,左右两条声明可以显式选择同一个 Receiver 串口。若端口实际连接的是直连有线手套,重复绑定会被拒绝。Receiver 中已配置但在 SDK 创建期间离线的手套不会加入:其他在线手套和不依赖该手套的 SDK 功能可以继续使用,离线 source 及其关联输出不会加入当前 SDK 实例。打开该手套后需要重新创建 SDK,不会在运行中的实例里动态加入。

经过身份确认的 Receiver source 支持 pose、status、Capture、Calibration、Skeleton 和 Retargeting。当前不提供无线 haptics 或未公开的设备控制能力;需要这些能力时请使用产品明确支持的连接方式。

选择和查看设备

Sdk 构造在返回前完成设备发现和身份校验。创建成功后即可选择设备和准备数据读取;持续 callback 建议在 start() 前注册。依赖串口自动发现时,Sdk 构造会访问设备;发现失败或身份约束不满足会直接导致构造失败。

直连手套在 Sdk 创建时按下图分配:

流程图渲染中

选择设备

配置中只有一只启用手套时,可直接选择:

auto glove = sdk.glove();
auto device = glove.device();

多手套场景可按 side 选择:

auto glove = sdk.glove();
auto left = glove.device(qnbot::Side::left);
auto right = glove.device(qnbot::Side::right);
  • 没有匹配设备时抛出 NotFoundSelectionError。
  • 匹配多个设备时抛出 AmbiguousSelectionError。
  • candidates() 提供可选设备,selector_kind() 和 selector_value() 描述本次选择。

选中的设备的 start()、stop() 与 health() 作用范围见 核心对象与生命周期。

查看设备

device.get_device_info() 返回 SDK 构造期间保存的已验证 GloveDeviceInfo 快照,包括 canonical_sn、设备类型、型号、固件版本、hand 和 hand 来源,不会每次重新发送身份命令。

设备标识的用途不同:

标识来源用途
nameGloveConfig::name,可选应用自己的逻辑名称;唯一设备或按 side 已能区分时可以不填,同侧多设备或复杂拓扑建议填写,并用 glove.device(name) 选择
source_idGloveDevice::source_id()SDK 为当前 source 提供的稳定路由标识
canonical_snget_device_info().canonical_sn经过设备身份验证的规范 SN,不应由应用根据端口或 name 推导

对显式 port + side 连接且无法提供身份的旧固件,SDK 不会伪造这些字段,调用会抛出 UnavailableFeatureError,依赖已验证身份的能力不可用。