From 2a69f92bb131ca598ef3fbd377b5e78aa35290fe Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld <67074795+PavelGuzenfeld@users.noreply.github.com> Date: Wed, 15 Apr 2026 23:20:43 +0300 Subject: [PATCH] fix(uxrce_dds_client): fix session reconnection after agent restart (#26848) * fix(uxrce_dds_client): fix session reconnection after agent restart When the Micro XRCE-DDS Agent is restarted (e.g. via systemd or Docker), the PX4 client stays "Running, disconnected" forever and never re-establishes the session. Three bugs prevented reconnection: 1. session.on_pong_flag was never reset after being checked. Once set to 1 by the first successful pong, it stayed 1 forever, causing checkConnectivity() to believe pings were still succeeding even after the agent was gone. Fixed by resetting to 0 after reading. 2. _subs->reset() was never called during session teardown. Stale uORB file descriptors from the previous session persisted across reconnection attempts, causing the new session's publishers to malfunction. Fixed by calling _subs->reset() in deleteSession(). 3. _connected was not explicitly reset in deleteSession(). While the outer loop checked this flag, explicitly clearing it ensures clean state for the next reconnection attempt. Closes #26022 Signed-off-by: Pavel Guzenfeld * fix(uxrce_dds_client): clear fds[].events in reset() for reconnection Without clearing events, init() skips orb_subscribe() on reconnect because the POLLIN guard (fds[idx].events == 0) is never true again. This causes all fds to remain at -1, px4_poll() returns 0, TX rate stays zero, and the client enters a disconnect/reconnect loop. Reported-by: sansha (tested on Pixhawk 6X with serial transport) * ci: re-trigger SITL tests (flaky offboard test) * docs(uxrce_dds_client): explain why reset() clears fds[].events --------- Signed-off-by: Pavel Guzenfeld --- src/modules/uxrce_dds_client/dds_topics.h.em | 1 + src/modules/uxrce_dds_client/uxrce_dds_client.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/modules/uxrce_dds_client/dds_topics.h.em b/src/modules/uxrce_dds_client/dds_topics.h.em index e69c8cde90..1d7b15d69f 100644 --- a/src/modules/uxrce_dds_client/dds_topics.h.em +++ b/src/modules/uxrce_dds_client/dds_topics.h.em @@ -120,6 +120,7 @@ void SendTopicsSubs::reset() { send_subscriptions[idx].data_writer = uxr_object_id(0, UXR_INVALID_ID); orb_unsubscribe(fds[idx].fd); fds[idx].fd = -1; + fds[idx].events = 0; // force re-subscribe on reconnect (init() skips when events != 0) } }; diff --git a/src/modules/uxrce_dds_client/uxrce_dds_client.cpp b/src/modules/uxrce_dds_client/uxrce_dds_client.cpp index b773bc0e5e..26628a486b 100644 --- a/src/modules/uxrce_dds_client/uxrce_dds_client.cpp +++ b/src/modules/uxrce_dds_client/uxrce_dds_client.cpp @@ -386,6 +386,11 @@ void UxrceddsClient::deleteSession(uxrSession *session) _session_created = false; } + if (_subs) { + _subs->reset(); + } + + _connected = false; _last_payload_tx_rate = 0; _timesync.reset_filter(); } @@ -709,6 +714,7 @@ void UxrceddsClient::run() /* PONG_IN_SESSION_STATUS */ if (session.on_pong_flag == 1) { _had_ping_reply = true; + session.on_pong_flag = 0; } // Calculate the payload tx/rx rate for connectivity monitoring @@ -720,6 +726,7 @@ void UxrceddsClient::run() perf_end(_loop_perf); } + PX4_INFO("session disconnected, attempting to reconnect..."); deleteSession(&session); } }