Skip to content

Commit 9582cea

Browse files
author
Ravi Singh
committed
fix(motion): debounce direction chip — 10 cm/s threshold, 200 ms commit
The Live tab's direction chip (still / closer → / away →) was flipping every 200 ms or so even when the target was stationary. Cause: the Kalman direction logic used a 4 cm/s velocity threshold + a 3-tick (60 ms) hysteresis, which is far below the LD2450's noise floor. Breathing-level sway easily crossed 4 cm/s, the chip flipped, layout felt twitchy. - Velocity threshold raised 4 → 10 cm/s. Whatever the radar's noise floor is, the velocity threshold needs a healthy multiple over it; 10 cm/s gives ~5x headroom over LD2450's ±5–10 cm position noise amplified to velocity by the Kalman filter. - Direction commit count raised 3 → 10 ticks (motion task @ 50 Hz, so 60 ms → 200 ms). 200 ms feels deliberate, doesn't lag for genuine movement, but rejects breathing/sway-level blips. - PI mode threshold also bumped 4 → 10 cm/s. PI has no agreement-count hysteresis (legacy v5 path), so threshold is the only knob there. Bench-tested on the same C3 + LD2450: chip now sits stably on "still" during normal standing-around behaviour, flips to "closer →" / "away →" within ~200 ms of a deliberate step.
1 parent f6a43ef commit 9582cea

2 files changed

Lines changed: 18 additions & 9 deletions

File tree

firmware/components/motion/motion.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ static void run_pi(float filtered_raw, float dt, target_t *t) {
133133
t->distance_cm = (int16_t)final_d;
134134
/* PI mode reports raw sensor direction; smoothed velocity sign is
135135
* noisy near zero, so users get cleaner direction in Kalman mode. */
136-
if (s_m.velocity > 4.f) t->direction = 1;
137-
else if (s_m.velocity < -4.f) t->direction = -1;
136+
if (s_m.velocity > 10.f) t->direction = 1;
137+
else if (s_m.velocity < -10.f) t->direction = -1;
138138
}
139139

140140
static void run_kalman(float filtered_raw, uint8_t energy, float dt, target_t *t) {
@@ -144,9 +144,13 @@ static void run_kalman(float filtered_raw, uint8_t energy, float dt, target_t *t
144144
if (predicted < s_m.min_cm) predicted = s_m.min_cm;
145145
if (predicted > s_m.max_cm) predicted = s_m.max_cm;
146146
t->distance_cm = (int16_t)predicted;
147-
/* Direction with hysteresis. 4 cm/s threshold: below this we treat the
148-
* target as stationary (returns 0). */
149-
t->direction = kalman_direction(&s_m.kf, vel, 4.f);
147+
/* Direction with hysteresis. 10 cm/s threshold: below this we treat the
148+
* target as stationary. Bumped from 4 cm/s on 2026-05-07 — at 4 cm/s,
149+
* a stationary person's breathing-level sway easily crossed the
150+
* threshold and the chip flipped between still/closer/away every
151+
* ~200 ms. 10 cm/s requires actual deliberate movement to register,
152+
* which is what users perceive as "moving" anyway. */
153+
t->direction = kalman_direction(&s_m.kf, vel, 10.f);
150154
}
151155

152156
static void motion_task(void *arg) {

firmware/components/motion/motion_kalman.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,21 @@ int8_t kalman_direction(kalman_t *k, float vel, float vel_threshold_cm_s) {
9393
k->dir_agree = 0;
9494
return k->dir_committed;
9595
}
96-
/* Different from committed → require 3 in a row to flip. This kills
97-
* the per-tick direction jitter that radar produces near zero
98-
* crossings (where the smoothed velocity oscillates around 0). */
96+
/* Different from committed → require N consecutive ticks to flip.
97+
* The motion task ticks at ~50 Hz, so each agree count is ~20 ms.
98+
* Bumped from 3 (60 ms) to 10 (200 ms) on 2026-05-07 — at 3, a
99+
* brief velocity blip from breathing or jitter would flip the
100+
* chip; 200 ms requires the user to be genuinely moving for ~⅕ s
101+
* before the indicator commits. Combined with the 10 cm/s
102+
* velocity threshold (raised from 4 cm/s), this kills the rapid
103+
* still ↔ closer ↔ away oscillation users were seeing. */
99104
if (sign == k->dir_pending) {
100105
if (k->dir_agree < 255) k->dir_agree++;
101106
} else {
102107
k->dir_pending = sign;
103108
k->dir_agree = 1;
104109
}
105-
if (k->dir_agree >= 3) {
110+
if (k->dir_agree >= 10) {
106111
k->dir_committed = k->dir_pending;
107112
k->dir_agree = 0;
108113
}

0 commit comments

Comments
 (0)