diff --git a/include/config.h b/include/config.h index fc54a99..4117e2e 100644 --- a/include/config.h +++ b/include/config.h @@ -24,6 +24,7 @@ #define PWM_RESOLUTION 8 // 8-bit resolution (0-255) #define PWM_CHANNEL_R 0 // LEDC channel for RPWM #define PWM_CHANNEL_L 1 // LEDC channel for LPWM +#define MIN_PWM_PERCENT 20 // Minimum PWM when motor is running (%) // Current Sense Configuration // BTS7960 current sense ratio: 8500:1 (kilo-amps) @@ -33,8 +34,10 @@ #define SENSE_RESISTOR 1000.0f // 1kΩ sense resistor (ohms) #define ADC_MAX 4095.0f // 12-bit ADC max value #define ADC_VREF 3.3f // ADC reference voltage -#define STALL_CURRENT_THRESHOLD 4.0f // Current (amps) that indicates stall -#define STALL_DETECT_TIME_MS 2500 // Time to confirm stall (ms) - accounts for startup inrush +#define CURRENT_CALIBRATION 0.33f // Calibration factor (measured current / reported current) +#define STALL_CURRENT_THRESHOLD 7.0f // Current (amps) that indicates stall +#define STALL_DETECT_TIME_MS 1000 // Time to confirm stall (ms) - accounts for startup inrush +#define DISABLE_STALL_DETECT false // Set to true to disable stall detection // Web Server #define HTTP_PORT 80 diff --git a/include/motor.h b/include/motor.h index ba1d434..d80bf04 100644 --- a/include/motor.h +++ b/include/motor.h @@ -23,13 +23,14 @@ public: void setStallCallback(void (*callback)(float current)); // Pingpong mode - void startPingpong(int speed, int timeMs, int speedRandomPercent, int timeRandomPercent); + void startPingpong(int speed, int timeMs, int speedRandomPercent, int timeRandomPercent, bool useStallReturn); void stopPingpong(); bool isPingpongActive(); int getPingpongSpeed(); int getPingpongTime(); int getPingpongSpeedRandom(); int getPingpongTimeRandom(); + bool getPingpongStallReturn(); private: int _speed = 0; @@ -50,6 +51,7 @@ private: int _pingpongCurrentTime = 2000; unsigned long _pingpongLastSwitch = 0; int _pingpongDirection = 1; + bool _pingpongUseStallReturn = false; // Return only after stall detection void applyMotorState(); float readCurrentSense(int pin); diff --git a/src/motor.cpp b/src/motor.cpp index fa00f2e..7906768 100644 --- a/src/motor.cpp +++ b/src/motor.cpp @@ -52,7 +52,7 @@ void MotorController::setDirection(int dir) { } void MotorController::stop() { - _speed = 0; + // Don't reset _speed - keep last speed setting _direction = 0; _stalled = false; _stallStartTime = 0; @@ -117,8 +117,14 @@ void MotorController::setStallCallback(void (*callback)(float current)) { } void MotorController::applyMotorState() { + // Apply minimum PWM when motor is running + int effectiveSpeed = _speed; + if (_speed > 0 && _speed < MIN_PWM_PERCENT) { + effectiveSpeed = MIN_PWM_PERCENT; + } + // Convert percentage to 8-bit PWM value - int pwmValue = map(_speed, 0, 100, 0, 255); + int pwmValue = map(effectiveSpeed, 0, 100, 0, 255); if (_direction == 0 || _speed == 0) { // Stop - both PWM outputs off @@ -151,6 +157,9 @@ float MotorController::readCurrentSense(int pin) { // Therefore: I_load = V * CURRENT_SENSE_RATIO / R_sense float current = (voltage * CURRENT_SENSE_RATIO) / SENSE_RESISTOR; + // Apply calibration factor (adjust for real-world measurement differences) + current *= CURRENT_CALIBRATION; + return current; #else return 0.0f; @@ -158,26 +167,31 @@ float MotorController::readCurrentSense(int pin) { } // Pingpong mode implementation -void MotorController::startPingpong(int speed, int timeMs, int speedRandomPercent, int timeRandomPercent) { +void MotorController::startPingpong(int speed, int timeMs, int speedRandomPercent, int timeRandomPercent, bool useStallReturn) { _pingpongBaseSpeed = constrain(speed, 0, 100); _pingpongBaseTime = constrain(timeMs, 100, 30000); _pingpongSpeedRandomPercent = constrain(speedRandomPercent, 0, 100); _pingpongTimeRandomPercent = constrain(timeRandomPercent, 0, 100); + _pingpongUseStallReturn = useStallReturn; _pingpongDirection = 1; _pingpongCurrentSpeed = applyRandomness(_pingpongBaseSpeed, _pingpongSpeedRandomPercent); - _pingpongCurrentTime = applyRandomness(_pingpongBaseTime, _pingpongTimeRandomPercent); + // Time randomness disabled when using stall return + _pingpongCurrentTime = _pingpongUseStallReturn ? _pingpongBaseTime : applyRandomness(_pingpongBaseTime, _pingpongTimeRandomPercent); _pingpongLastSwitch = millis(); _pingpongActive = true; + _stalled = false; // Reset stall state when starting pingpong + _stallStartTime = 0; // 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", + Serial.printf("Pingpong started: speed=%d%% (base=%d, rand=%d%%), time=%dms (base=%d, rand=%d%%), stallReturn=%s\n", _pingpongCurrentSpeed, _pingpongBaseSpeed, _pingpongSpeedRandomPercent, - _pingpongCurrentTime, _pingpongBaseTime, _pingpongTimeRandomPercent); + _pingpongCurrentTime, _pingpongBaseTime, _pingpongTimeRandomPercent, + _pingpongUseStallReturn ? "true" : "false"); } void MotorController::stopPingpong() { @@ -206,17 +220,41 @@ int MotorController::getPingpongTimeRandom() { return _pingpongTimeRandomPercent; } +bool MotorController::getPingpongStallReturn() { + return _pingpongUseStallReturn; +} + void MotorController::updatePingpong() { if (!_pingpongActive) return; + bool shouldSwitch = false; unsigned long now = millis(); - if ((now - _pingpongLastSwitch) >= (unsigned long)_pingpongCurrentTime) { - // Time to switch direction + + if (_pingpongUseStallReturn) { + // Switch direction only when stall is detected + if (_stalled) { + shouldSwitch = true; + Serial.println("Pingpong: stall detected, switching direction"); + } + } else { + // Time-based switching + if ((now - _pingpongLastSwitch) >= (unsigned long)_pingpongCurrentTime) { + shouldSwitch = true; + } + } + + if (shouldSwitch) { + // Switch direction _pingpongDirection = -_pingpongDirection; + // Reset stall state for new direction + _stalled = false; + _stallStartTime = 0; + // Apply randomness for next cycle _pingpongCurrentSpeed = applyRandomness(_pingpongBaseSpeed, _pingpongSpeedRandomPercent); - _pingpongCurrentTime = applyRandomness(_pingpongBaseTime, _pingpongTimeRandomPercent); + // Time randomness disabled when using stall return + _pingpongCurrentTime = _pingpongUseStallReturn ? _pingpongBaseTime : applyRandomness(_pingpongBaseTime, _pingpongTimeRandomPercent); _pingpongLastSwitch = now; // Apply new state @@ -224,8 +262,9 @@ void MotorController::updatePingpong() { _direction = _pingpongDirection; applyMotorState(); - Serial.printf("Pingpong switch: dir=%d, speed=%d%%, next_time=%dms\n", - _pingpongDirection, _pingpongCurrentSpeed, _pingpongCurrentTime); + Serial.printf("Pingpong switch: dir=%d, speed=%d%%, next_time=%dms, stallReturn=%s\n", + _pingpongDirection, _pingpongCurrentSpeed, _pingpongCurrentTime, + _pingpongUseStallReturn ? "true" : "false"); } } diff --git a/src/webserver.cpp b/src/webserver.cpp index c044c2c..9370251 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -199,8 +199,8 @@ const char index_html[] PROGMEM = R"rawliteral(
- +