3.6 KiB
ADR-094: Body Tracking Platform
Status
Accepted
Context
RuView currently detects presence and estimates person count via CSI variance heuristics and RF tomography cluster analysis. Individual body tracking (assigning persistent IDs, tracking movement over time, detecting room transitions) is missing. The pose_tracker module exists but operates on synthetic keypoints.
The voxel cluster system provides per-body centroid, bounding box, and pose hint. This is the foundation for tracking.
Note: Upstream ADR-081 (Adaptive CSI Mesh Firmware Kernel, accepted 2026-04-19) covers a different concern — firmware vtable and adaptive kernel selection. This ADR-094 covers the body-tracking layer and is numbered to avoid collision with that accepted ADR.
Decision
Build a body tracking layer on top of the existing cluster output that:
- Assigns persistent IDs to clusters across frames (Hungarian algorithm / nearest-neighbor)
- Tracks centroid trajectories with Kalman filtering for smooth paths
- Detects room zone membership (configurable zones via API)
- Emits tracking events to the event stream
- Exposes tracking state via REST API
Architecture
spatial_pipeline → find_body_clusters() → Vec<BodyCluster>
↓
body_tracker.rs → Vec<TrackedBody>
↓
zone_transitions → zone_enter/zone_exit events
↓
REST: /api/v1/tracking/bodies
REST: /api/v1/tracking/zones
WS: tracking_update messages
TrackedBody
struct TrackedBody {
id: u32, // persistent ID (increments, never reused in session)
centroid: [f64; 3], // current position (Kalman-filtered)
velocity: [f64; 3], // estimated velocity (m/s)
pose_hint: String, // standing/sitting/lying
zone: Option<String>, // current zone name
first_seen: Instant,
last_seen: Instant,
track_quality: f64, // 0-1, decays when cluster is missing
}
Association Algorithm
- Each frame: compute distance matrix between existing tracks and new clusters
- Greedy nearest-neighbor assignment (< 2m threshold)
- Unmatched clusters → new track
- Unmatched tracks → decay quality; remove after 20 absent frames
Zone System
- Zones defined as axis-aligned boxes in 3D space
- Configurable via
POST /api/v1/tracking/zones - Default: whole room = one zone
- Zone transitions emit
ZoneTransitionevents
Implementation
New file: body_tracker.rs
BodyTrackerstruct with track stateupdate(clusters: &[BodyCluster]) -> TrackingUpdate- Kalman filter (simple: position + velocity, 6-state)
- Zone membership check
- Self-contained:
BodyClusterdefined inline (no dependency on spatial_pipeline module)
Modified files
main.rs: addbody_trackermodule, wire tracker intoAppStateInner, add REST endpoints
API Endpoints
GET /api/v1/tracking/bodies— current tracked bodies with IDs and positionsGET /api/v1/tracking/zones— configured zonesPOST /api/v1/tracking/zones— add/update zoneDELETE /api/v1/tracking/zones/{name}— remove zone
Consequences
- Persistent body IDs enable time-series analytics
- Zone transitions enable room-level automation (lights, HVAC)
- Kalman smoothing reduces jitter from frame-to-frame cluster centroid noise
- Track quality metric lets UI show confidence in each detection
- Foundation for activity history, fall detection, sleep detection, and dashboard floor plan features