SDKC++ SDK

Device discovery & connection

Discover or fix a glove, select one or many, and use a Receiver.

Current version · 1.4.0

Device discovery & connection

The default configuration discovers the single supported serial glove. To fix a port or serial number, or to run multiple gloves, configure GloveConfig in the matching section below.

Device discovery

To list devices before creating the Sdk, call qnbot::discover_gloves(). The returned std::vector<qnbot::DiscoveredGlove> contains the serial port, left/right hand, device SN, and an optional per-device error:

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};
}

When the port is occupied by another process, the device is still kept in the result, port is usable, and the condition is identified by qnbot::GloveDiscoveryErrorCode::port_busy (stable error code PORT_BUSY). Program logic should test the enum and must not parse the diagnostic message. The discovery result is a snapshot of the moment of the call; rediscover after devices are plugged or unplugged. For a complete example, see discover_gloves.cpp.

Single glove

The single-glove scenario automatically discovers the only connected supported glove:

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

A single-glove declaration without a configured side still requires exactly one unoccupied candidate. Fixed selection is only needed when automatic discovery cannot work, see Connecting the device.

Two gloves

When connecting one left glove and one right glove at the same time, you only need to declare the side; there is no need to set connection explicitly:

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

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

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

The SDK assigns devices uniquely by side; the serial enumeration order does not determine the left/right data streams. Each directly wired glove is assigned at most once; a supported Receiver can carry two sources, left and right. SDK creation fails when the directly wired candidates are missing one side, when multiple candidates exist on the same side, or when the device information and the discovery result disagree during SDK creation. The behavior when a glove on a Receiver goes offline during SDK creation is described below. Two gloves on the same side must each explicitly configure port or serial_number.

When no device locating information is provided, SerialConnection{} uses the automatic discovery and side assignment described above.

Multiple gloves

When connecting three or more gloves, at least two are on the same side. To select each glove individually, set a unique name for each entry and use different port or serial_number values to pin down same-side gloves. name is only used by the application to select a glove and does not replace device locating information; if the other conditions are already unique, the SDK does not reject creation merely because name is omitted.

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");

No physical glove, or integrating your own device? Both cases can feed external hand frames frame by frame, and they are read through the same paths as a physical glove. See External input for the configuration and frame constraints.

Connecting the device

Sdk construction completes device discovery and identity verification before returning; start() establishes the continuously running connection and data streams, see Lifecycle. Use the connection options below when you need to pin a specific device.

A fixed port or serial number

A fixed deployment can specify the serial port:

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

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

When the SDK can recognize the port as a supported directly wired glove and both port and side are explicitly provided, the SDK still verifies the device identity first. For older directly wired gloves that cannot report a device identity, the SDK continues to connect using the configured serial port and left/right hand, and emits an "identity not verified" warning. Reconnection after a drop retries only that port and cannot confirm whether the recovered device is still the same physical glove. Automatic discovery, providing only port, providing only side, selecting by serial_number, wireless Receivers, and unrecognized port types still require device identity verification and cannot use this compatibility behavior.

You can also select by USB serial number. An empty SerialConnection{} uses automatic discovery:

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

When device locating information is set explicitly, auto_discover=true, port and serial_number are mutually exclusive; baudrate is optional.

Wireless Receiver (experimental)

The Receiver is currently an experimental feature; its stability, support scope, and public behavior may change later, and the current behavior should not be treated as a long-term compatibility commitment.

A supported wireless Receiver uses the same qnbot::GloveConfig and serial port selection method as a directly wired glove; no Receiver-specific configuration type is needed. One declaration still represents only one glove source; to connect the left and right hands automatically, declare qnbot::Side::left and qnbot::Side::right separately, and the SDK can resolve the gloves on both sides through the same Receiver.

For fixed deployments, the left and right declarations can explicitly select the same Receiver serial port. If the port is actually connected to a directly wired glove, duplicate binding is rejected. A glove on the Receiver that is configured but offline during SDK creation is not added: other online gloves and SDK capabilities that do not depend on that glove can continue to be used, and the offline source and its associated outputs are not added to the current SDK instance. After turning that glove on, the SDK must be recreated; it is not added dynamically to a running instance.

An identity-confirmed Receiver source supports pose, status, Capture, Calibration, Skeleton, and Retargeting. Wireless haptics and undocumented device control capabilities are not currently provided; when these capabilities are needed, use a connection method that the product explicitly supports.

Select and inspect a device

Sdk construction completes device discovery and identity verification before returning. Once creation succeeds, you can select devices and prepare data reads; continuous callbacks are best registered before start(). When relying on serial auto-discovery, Sdk construction accesses the devices; a discovery failure or unmet identity constraints directly makes construction fail.

Direct gloves are allocated when the Sdk is created, as shown below:

Rendering diagram

Select a device

When only one glove is enabled in the configuration, you can select it directly:

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

In multi-glove scenarios, you can select by side:

auto glove = sdk.glove();
auto left = glove.device(qnbot::Side::left);
auto right = glove.device(qnbot::Side::right);
  • When no device matches, NotFoundSelectionError is thrown.
  • When multiple devices match, AmbiguousSelectionError is thrown.
  • candidates() provides the selectable devices, and selector_kind() and selector_value() describe this selection.

Inspect the device

device.get_device_info() returns the verified GloveDeviceInfo snapshot saved during SDK construction, including canonical_sn, device type, model, firmware version, hand, and hand source; it does not resend the identity command each time.

Device identifiers serve different purposes:

IdentifierSourcePurpose
nameGloveConfig::name, optionalThe application's own logical name; it can be left empty when the device is unique or can already be distinguished by side; it is recommended for multiple devices on the same side or complex topologies, and is used to select with glove.device(name)
source_idGloveDevice::source_id()A stable routing identifier provided by the SDK for the current source
canonical_snget_device_info().canonical_snThe canonical SN verified through device identity; the application should not derive it from the port or name

For legacy firmware connected with an explicit port + side that cannot provide an identity, the SDK does not fabricate these fields; the call throws UnavailableFeatureError, and capabilities that depend on a verified identity are unavailable.

GloveDevice's start() and stop() act only on that device. The same-named operations on Glove act on all configured gloves.