feat: add simple stall detection with threshold + debounce

- Add STALL_THRESHOLD (8A) and STALL_CONFIRM_SAMPLES (3) config
- Add 500ms stabilization delay after direction change to prevent false positives
- Add stall warning banner in web UI
- Stop motor and pingpong when stall detected

Algorithm: If active current > 8A for 3 consecutive samples (300ms),
and motor has been running for at least 500ms, trigger stall callback.
This commit is contained in:
devdesk
2026-02-05 21:29:38 +02:00
parent 3aec7250c9
commit dffb859826
5 changed files with 119 additions and 2 deletions

View File

@@ -109,6 +109,19 @@ const char index_html[] PROGMEM = R"rawliteral(
border-top: 2px solid #0f3460;
margin: 30px 0;
}
.stall-warning {
background: #ff5252;
color: white;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
font-weight: bold;
font-size: 18px;
display: none;
}
.stall-warning.active {
display: block;
}
.pingpong-section {
background: #16213e;
padding: 20px;
@@ -169,6 +182,8 @@ const char index_html[] PROGMEM = R"rawliteral(
<div class="container">
<h1>Motor Control</h1>
<div class="stall-warning" id="stallWarning">⚠️ STALL DETECTED!</div>
<div class="current-display">
<div>
<div class="current-label">CURRENT R</div>
@@ -323,6 +338,14 @@ const char index_html[] PROGMEM = R"rawliteral(
document.getElementById('currentR').textContent = data.currentR.toFixed(2);
document.getElementById('currentL').textContent = data.currentL.toFixed(2);
// Update stall warning
const stallWarning = document.getElementById('stallWarning');
if (data.stalled) {
stallWarning.classList.add('active');
} else {
stallWarning.classList.remove('active');
}
// Update pingpong status
if (data.pingpong) {
ppStatus.textContent = 'ACTIVE';
@@ -387,6 +410,7 @@ void handleStatus() {
",\"direction\":" + String(motor.getDirection()) +
",\"currentR\":" + String(motor.getCurrentRight(), 2) +
",\"currentL\":" + String(motor.getCurrentLeft(), 2) +
",\"stalled\":" + (motor.isStalled() ? "true" : "false") +
",\"pingpong\":" + (motor.isPingpongActive() ? "true" : "false") +
",\"ppSpeed\":" + String(motor.getPingpongSpeed()) +
",\"ppTime\":" + String(motor.getPingpongTime()) +