Skip to content

feat(core): add heartbeat watchdog (deadman timer) (#2895)#2905

Open
tpayne-censystech wants to merge 3 commits into
mavlink:mainfrom
tpayne-censystech:feat-2895
Open

feat(core): add heartbeat watchdog (deadman timer) (#2895)#2905
tpayne-censystech wants to merge 3 commits into
mavlink:mainfrom
tpayne-censystech:feat-2895

Conversation

@tpayne-censystech

Copy link
Copy Markdown

Implements external control of MAVSDK heartbeat emission, per the API added in mavlink/MAVSDK-Proto#415.

When enabled, this disables MAVSDK's internally generated HEARTBEAT sending and drives emission from the client via a runtime-configurable deadman timeout. The client refreshes within the timeout to keep heartbeats flowing; if it crashes, disconnects, or stops servicing the path, MAVSDK stops sending, so PX4 sees the GCS/companion component go offline and triggers the configured lost-link failsafe (e.g. RTL). MAVSDK continues to own heartbeat content (sysid, compid, mav_type, etc.); the client only controls whether emission continues. Default behavior is unchanged.

Includes the proto submodule bump to the merged commit, regenerated mavsdk_server code, and the core implementation with tests.

Depends on mavlink/MAVSDK-Proto#415 (merge first).

Closes #2895

Contributed by Tyler Payne on behalf of Censys Technologies, Inc.

While a watchdog timeout is configured, MAVSDK's periodic heartbeats
are only sent as long as the watchdog keeps being fed at least once per
timeout period, so heartbeats reflect the liveness of the client
application.

- Configure via Configuration::set_heartbeat_watchdog_timeout_s() or at
  runtime via Mavsdk::set_heartbeat_watchdog_timeout_s(); must be 0
  (disabled) or at least 1 second.
- Feed via Mavsdk::feed_heartbeat_watchdog() (C++/C API) or the
  FeedHeartbeatWatchdog gRPC RPC. Also exposed as the
  SetHeartbeatWatchdogTimeout RPC (proto submodule bump) and the
  mavsdk_server --heartbeat-watchdog-timeout CLI option.
- Heartbeats latch off until fed: on enable, timeout change, expiry,
  and any other stop (e.g. disconnect), so a dead client cannot emit
  heartbeats across reconnects or discovery. A feed only restarts
  heartbeats that are supposed to be sent (always_send_heartbeats or a
  connected system).
- Watchdog state is guarded by _heartbeat_mutex with a generation
  counter against in-flight expiries; configuration writers are
  serialized on a dedicated mutex, and heartbeat starts/stops self-heal
  against stale policy snapshots.
- Unit tests (expiry, latching, policy, feed restart, reconfiguration,
  stress) and gRPC service tests.
@julianoes

Copy link
Copy Markdown
Collaborator

Thanks @tpayne-censystech, let me check CI, once that passes I'll merge the proto PR, and then update this PR and then merge it.

Use a checked-out MAVLink channel for test inject packing, and define
MavlinkChannels::Instance() in the .cpp so shared builds share one allocator.
@tpayne-censystech

tpayne-censystech commented Jul 17, 2026

Copy link
Copy Markdown
Author

@julianoes , I tried to fix the CI but I can't get it to run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for disabling native heartbeat sending and triggering HEARTBEAT over gRPC

2 participants