github ruvnet/RuView multistatic-timing-fixes-2026-09-09
Multistatic timing & positioning fixes — 2026-09-09

latest release: v2617
3 hours ago

RuView multistatic timing & positioning fixes — 2026-09-09

Nine community contributions landed today, all focused on one theme: getting multiple sensor nodes to actually agree on the same physical moment and the same physical location. That sounds basic, but it turns out to be the hardest part of making several WiFi sensors work together as one system instead of three independent guesses.

What actually changes

Nodes now measure their own speed correctly, even when data arrives in bursts.
The counter that tracks how fast a sensor is really sending data was quietly wrong whenever packets clumped together (which happens constantly over WiFi/UDP) — a burst of several readings in quick succession got counted as just one, so the system underestimated how fast a node was actually running. Fixed by measuring time gaps the right way around, so the reported speed now matches reality.

Multiple sensors can finally look at the same instant in time.
Each sensor used to decide "have 20 milliseconds passed since MY last reading?" independently — which meant two perfectly healthy sensors, both running at the right speed, could end up sampling completely different moments, with nothing in common to compare. The fix synchronizes that decision to a shared clock across the mesh, so sensors that are supposed to be looking at the same moment now actually are — a prerequisite for combining several sensors' views into one accurate picture.

A safety check that was supposed to catch bad timing... never actually could.
A guard rail meant to reject data if sensors were too out-of-sync had a math error: it was checking the wrong quantity, so it would never trigger even when it should have. Now fixed and verified with a real end-to-end test.

Room positions are now correctly remembered, even when a sensor briefly drops out.
This is a fix to something we shipped five days ago — thank you to the contributor who caught it. The original fix (assigning each sensor's configured position by "the Nth sensor currently online") had a subtle flaw: if one sensor went quiet, every sensor after it in the lineup would silently inherit the wrong position, since they'd all shift up one slot. Positions are now tied permanently to each sensor's actual ID, so a sensor going offline no longer scrambles everyone else's coordinates.

New optional antenna-selection support for a specific hardware variant (Seeed XIAO ESP32-C6), letting that board choose between its internal and external antenna — useful for controlled signal-strength comparisons. Fully opt-in; does nothing on other boards.

Documentation additions: a from-the-field operational runbook for flashing and running the ESP32-C6 firmware (the kind of guide written after getting each step wrong at least once), an architecture record explaining why device-free position estimation kept failing and what was learned from measuring it three different ways, and a rigorously honest write-up of a real nine-sensor experiment comparing three different timing strategies — including a reported prediction that turned out wrong and a mid-experiment methodology hiccup, disclosed rather than hidden.

Thank you to this round's contributors

  • clonea1 — eight of today's nine contributions: the burst-timing fix, mesh-time alignment, the timing-guard math fix, the node-position correction (including catching a real bug in code merged five days ago), the antenna-selection groundwork's supporting docs, the operational runbook, the architecture record, and the measured timing-gate comparison.
  • proffesor-for-testing (Dragan Spiridonov) — the XIAO ESP32-C6 antenna-selection feature.

Every change here was independently verified against the actual running code before merging — not just taken on the strength of its description.

What this doesn't include

Two related, still-open gaps surfaced during review, not fixed by this batch:

  • The governed fusion path (the one that actually feeds provenance and trust tracking) still has its own separate instance of the position-tracking system that was never wired up to use configured positions at all — a different code path from the one fixed here. Tracked in #1870.
  • A large, well-documented field report (#1804) raising real architecture questions about occupancy counting, still-person detection, and automatic gain control — partially answered, with several questions still needing the maintainer's own call on intended design.

Merged pull requests

PR Title Contributor
#1855 chore: ignore host-test binaries by shape, not by a list that goes stale clonea1
#1857 fix(server): recover the true CSI frame rate through bursty UDP delivery clonea1
#1858 docs: measured comparison of three CSI frame-selection gates, and the harness clonea1
#1859 feat(firmware): align the CSI rate gate to mesh time clonea1
#1860 fix(sensing-server): key node positions by node id, not by list position clonea1
#1861 docs(firmware): add the ESP32-C6 operational runbook clonea1
#1862 docs(adr): ADR-345 — per-link CSI attribution and node-to-node ranging clonea1
#1867 feat(firmware): add XIAO ESP32-C6 antenna selection proffesor-for-testing
#1872 fix(signal): the derived soft guard flagged the schedule it was derived from clonea1

All nine were independently reviewed against the underlying code before merge, including one merge-conflict resolution (#1858 vs. an unrelated concurrently-merged docs PR) handled during integration.

Known open issues (not fixed by this batch)

  • #1870 — the governed StreamingEngine fusion path owns a separate MultistaticFuser instance that is never configured with node positions at all; distinct from the instance fixed in #1860.
  • #1804 — detailed field report on occupancy-counting and still-person-detection gaps; partially addressed in comments, several architecture questions remain open for maintainer input.

Don't miss a new RuView release

NewReleases is sending notifications on new releases.