Add pingpong mode with speed, time, and randomness settings

- Add pingpong oscillation mode that alternates motor direction
- Settings: base speed (10-100%), time before return (0.5-10s)
- Randomness controls for both speed (0-50%) and time (0-50%)
- Web UI with sliders and start/stop buttons
- API endpoints: /pingpong/start and /pingpong/stop
- Real-time status polling shows pingpong active state
This commit is contained in:
devdesk
2026-02-05 17:06:12 +02:00
parent e2fe9aa495
commit ba27db4f55
3 changed files with 313 additions and 19 deletions

View File

@@ -78,6 +78,9 @@ void MotorController::update() {
// Check for stall condition
checkStall();
#endif
// Update pingpong mode
updatePingpong();
}
int MotorController::getSpeed() {
@@ -154,6 +157,89 @@ float MotorController::readCurrentSense(int pin) {
#endif
}
// Pingpong mode implementation
void MotorController::startPingpong(int speed, int timeMs, int speedRandomPercent, int timeRandomPercent) {
_pingpongBaseSpeed = constrain(speed, 0, 100);
_pingpongBaseTime = constrain(timeMs, 100, 30000);
_pingpongSpeedRandomPercent = constrain(speedRandomPercent, 0, 100);
_pingpongTimeRandomPercent = constrain(timeRandomPercent, 0, 100);
_pingpongDirection = 1;
_pingpongCurrentSpeed = applyRandomness(_pingpongBaseSpeed, _pingpongSpeedRandomPercent);
_pingpongCurrentTime = applyRandomness(_pingpongBaseTime, _pingpongTimeRandomPercent);
_pingpongLastSwitch = millis();
_pingpongActive = true;
// Apply initial state
_speed = _pingpongCurrentSpeed;
_direction = _pingpongDirection;
applyMotorState();
Serial.printf("Pingpong started: speed=%d%% (base=%d, rand=%d%%), time=%dms (base=%d, rand=%d%%)\n",
_pingpongCurrentSpeed, _pingpongBaseSpeed, _pingpongSpeedRandomPercent,
_pingpongCurrentTime, _pingpongBaseTime, _pingpongTimeRandomPercent);
}
void MotorController::stopPingpong() {
_pingpongActive = false;
stop();
Serial.println("Pingpong stopped");
}
bool MotorController::isPingpongActive() {
return _pingpongActive;
}
int MotorController::getPingpongSpeed() {
return _pingpongBaseSpeed;
}
int MotorController::getPingpongTime() {
return _pingpongBaseTime;
}
int MotorController::getPingpongSpeedRandom() {
return _pingpongSpeedRandomPercent;
}
int MotorController::getPingpongTimeRandom() {
return _pingpongTimeRandomPercent;
}
void MotorController::updatePingpong() {
if (!_pingpongActive) return;
unsigned long now = millis();
if ((now - _pingpongLastSwitch) >= (unsigned long)_pingpongCurrentTime) {
// Time to switch direction
_pingpongDirection = -_pingpongDirection;
// Apply randomness for next cycle
_pingpongCurrentSpeed = applyRandomness(_pingpongBaseSpeed, _pingpongSpeedRandomPercent);
_pingpongCurrentTime = applyRandomness(_pingpongBaseTime, _pingpongTimeRandomPercent);
_pingpongLastSwitch = now;
// Apply new state
_speed = _pingpongCurrentSpeed;
_direction = _pingpongDirection;
applyMotorState();
Serial.printf("Pingpong switch: dir=%d, speed=%d%%, next_time=%dms\n",
_pingpongDirection, _pingpongCurrentSpeed, _pingpongCurrentTime);
}
}
int MotorController::applyRandomness(int baseValue, int randomPercent) {
if (randomPercent == 0) return baseValue;
int maxVariation = (baseValue * randomPercent) / 100;
int variation = random(-maxVariation, maxVariation + 1);
int result = baseValue + variation;
// Ensure result stays positive and reasonable
return max(1, result);
}
void MotorController::checkStall() {
#if CURRENT_SENSING_ENABLED
// Only check stall when motor should be running