From 2971e46881cf937791f96968a0f3b0710dad232a Mon Sep 17 00:00:00 2001 From: Lotus Li Date: Wed, 7 Oct 2026 01:10:27 +0000 Subject: [PATCH 1/2] [merge-to-it] sharpa_avatar: judge glove liveness by fetched data, not the online flag AvatarDevice::get_device_info().online stays false for a glove first discovered offline and powered on later, so such a glove was started and then stopped every 2 s. refresh_data() no longer checks that flag; a glove is disconnected only after the data timeout. Workaround for #1181. Signed-off-by: Lotus Li --- .../sharpa_avatar/core/avatar_hand_tracking_plugin.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp b/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp index 3c89185b00..8742f57ed2 100644 --- a/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp +++ b/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp @@ -428,11 +428,8 @@ void AvatarTracker::refresh_data() { continue; } - if (!state.device->get_device_info().online) - { - state.reset(); - continue; - } + // Liveness comes from fetched data, not get_device_info().online: the SDK + // leaves that flag false on a glove first discovered offline and powered on later. const bool expects_data = m_config.human || m_config.raw || m_config.robot; // fetch_data() keeps returning a silent glove's last sample, so only a newer From 0c87e8a3c84704fea513e686f1b9e1f0de04489a Mon Sep 17 00:00:00 2001 From: Lotus Li Date: Thu, 8 Oct 2026 12:19:55 -0700 Subject: [PATCH 2/2] [merge-to-it] sharpa_avatar: time out a haptic-only glove by its RAW stamps With --datasets=haptic nothing dropped a glove's handle once the online reset was removed: the data timeout was gated on a data dataset and set_task() failures only log. A power-cycled glove kept its dead handle, which blocked reconnection. A haptic-only glove now fetches RAW so the same stamp-based data timeout applies to every configuration. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Lotus Li --- .../core/avatar_hand_tracking_plugin.cpp | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp b/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp index 8742f57ed2..fa42251877 100644 --- a/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp +++ b/src/plugins/sharpa_avatar/core/avatar_hand_tracking_plugin.cpp @@ -430,8 +430,9 @@ void AvatarTracker::refresh_data() } // Liveness comes from fetched data, not get_device_info().online: the SDK // leaves that flag false on a glove first discovered offline and powered on later. + // A haptic-only glove still fetches RAW so the data timeout below can drop a dead handle. + const bool probe_raw = !m_config.human && !m_config.raw && !m_config.robot; - const bool expects_data = m_config.human || m_config.raw || m_config.robot; // fetch_data() keeps returning a silent glove's last sample, so only a newer // sample stamp counts as data for the timeout below. bool fetched_any = false; @@ -461,7 +462,7 @@ void AvatarTracker::refresh_data() } for (const ::avatar::DeviceDataCategory category : kJointDataCategories) { - if (!dataset_enabled(category)) + if (!dataset_enabled(category) && !(probe_raw && category == ::avatar::DeviceDataCategory::RAW)) { continue; } @@ -478,18 +479,15 @@ void AvatarTracker::refresh_data() cached = {}; } } - if (expects_data) + const auto now = std::chrono::steady_clock::now(); + if (fetched_any) { - const auto now = std::chrono::steady_clock::now(); - if (fetched_any) - { - state.last_successful_fetch = now; - } - else if (!state.last_successful_fetch || now - *state.last_successful_fetch >= kAvatarDataTimeout) - { - logger()->warn("{} glove disconnected: no data for {} s.", to_string(side), kAvatarDataTimeout.count()); - state.reset(); - } + state.last_successful_fetch = now; + } + else if (!state.last_successful_fetch || now - *state.last_successful_fetch >= kAvatarDataTimeout) + { + logger()->warn("{} glove disconnected: no data for {} s.", to_string(side), kAvatarDataTimeout.count()); + state.reset(); } } }